
인터페이스의 마지막 입력 및 출력을 표시하는 Cisco 스위치의 출력을 유용한 형식으로 변환할 수 있는 스크립트를 만들려고 합니다. 이는 예를 들어 지난 6개월 동안 어떤 인터페이스가 사용되지 않았는지 알 수 있도록 하기 위함입니다. Cisco에서는 인터페이스에 대한 마지막 입력이 10w4d
.
지금까지 얻은 것은 다음과 같은 입력 파일입니다.
FastEthernet0/4,3 days ago,3 days ago
FastEthernet0/8,46 years ago ,46 years ago
FastEthernet0/10,46 years ago ,46 years ago
FastEthernet0/11,46 years ago ,46 years ago
FastEthernet0/12,08:47:53,04:00:32
FastEthernet0/13,1 year ago 46 weeks ago ,1 year ago 46 weeks ago
FastEthernet0/14,46 years ago ,46 years ago
FastEthernet0/15,13 weeks ago 4 days ago ,13 weeks ago 4 days ago
FastEthernet0/16,46 years ago ,46 years ago
FastEthernet0/18,46 years ago ,46 years ago
FastEthernet0/19,46 years ago ,46 years ago
FastEthernet0/20,46 years ago ,46 years ago
FastEthernet0/22,46 years ago ,1 year ago 50 weeks ago
FastEthernet0/24,46 years ago ,46 years ago
유효한 날짜를 얻을 수 있도록 Never Last Input and Output 상태의 모든 인터페이스를 46년 전으로 설정했습니다. 예, 이를 고려할 수 있는 가동 시간 기록이 있습니다.
내 문제는 이제 유효한 날짜로 변환하려고 한다는 것입니다. 이렇게 하면 awk
정상적으로 작동합니다.xargs
awk -F, '{print $2}' tst | xargs -i date -d "{}" +%Y-%m-%d
나는 다음과 같은 응답을 받았습니다.
2016-08-18
1970-08-21
1970-08-21
1970-08-21
2016-08-21
2014-10-03
1970-08-21
2016-05-18
1970-08-21
1970-08-21
1970-08-21
1970-08-21
1970-08-21
1970-08-21
하지만 이렇게 하면 다음과 같은 결과가 나올 것 같습니다.
awk -F, -v OFS="," '{
cmd2=("date \"+'%Y-%m-%d'\" -d \""$2 "\"")
cmd2|getline d2
print cmd2,d2
}' tst
나는 다음과 같은 응답을 받았습니다.
date "+%Y-%m-%d" -d "3 days ago",2016-08-18
date "+%Y-%m-%d" -d "46 years ago ",1970-08-21
date "+%Y-%m-%d" -d "46 years ago ",1970-08-21
date "+%Y-%m-%d" -d "46 years ago ",1970-08-21
date "+%Y-%m-%d" -d "08:47:53",2016-08-21
date "+%Y-%m-%d" -d "1 year ago 46 weeks ago ",2014-10-03
date "+%Y-%m-%d" -d "46 years ago ",2014-10-03
date "+%Y-%m-%d" -d "13 weeks ago 4 days ago ",2016-05-18
date "+%Y-%m-%d" -d "46 years ago ",2016-05-18
date "+%Y-%m-%d" -d "46 years ago ",2016-05-18
date "+%Y-%m-%d" -d "46 years ago ",2016-05-18
date "+%Y-%m-%d" -d "46 years ago ",2016-05-18
date "+%Y-%m-%d" -d "46 years ago ",2016-05-18
date "+%Y-%m-%d" -d "46 years ago ",2016-05-18
cmd2
방금 명령에 추가하여 어떤 작업을 수행하는지 확인했습니다. print
이 명령을 실행하면 정확한 날짜가 표시됩니다.
간단한 내용이 빠진 것 같은데 3~4시간 동안 반복해서 시도한 결과 이제 다시 한 번 살펴보고 싶습니다.
누군가 나에게 올바른 방향을 알려줄 수 있습니까?
고쳐 쓰다! Stephen도 지적했듯이 입력 파일 세 줄만 있어도 아무런 문제가 없었습니다. 테스트되지 않은 시나리오를 게시하여 죄송합니다.
답변1
이 작업을 수행할 때:
cmd = "some command"
cmd | getline d2
cmd | getline d2
에서 awk
첫 번째는 getline
출력의 첫 번째 줄(레코드)을 가져오고 두 번째는 두 번째 줄을 가져옵니다. 출력의 끝에 도달하면 0이 반환됩니다.cmd
cmd
getline
getline
귀하의 경우 cmd = "date -d \"46 years ago\""
명령은 한 줄만 출력하므로 첫 번째 명령은 해당 줄 과 양수를 getline
반환 하지만 두 번째 명령은 도착하므로 0을 반환하고 변경되지 않습니다.d2
eof
d2
여기에는 다음이 필요합니다.
cmd | getline d2; close(cmd)
그래서 cmd
매번 실행해야 합니다.
또는 동일한 매개변수로 동일한 명령을 여러 번 실행하지 않도록 출력을 cmd
해시에 저장합니다.
if (!($2 in cache)) {cmd=...; cmd | getline cache[$2]; close(cmd)}
print cache[$2]
cmd
많은 파일 설명자를 열지 않으려면 해당 위치를 닫는 것이 좋습니다.
close(cmd)
when 의 모호성은 및 cmd
에 모두 적용됩니다 . 폐쇄 여부getline < cmd
cmd | getline
cmd
주문하다또는cmd
문서아니면 둘다?
$ cat test.awk
BEGIN{
OFS=","
getline a1 < "uname"
"uname" | getline b1
close("uname")
getline a2 < "uname"
"uname" | getline b2
print a1,b1,a2,b2
}
$ echo test > uname
$ mawk -f test.awk
test,Linux,test,Linux
$ bwk-awk -f test.awk
test,Linux,test,Linux
$ gawk -f test.awk
test,Linux,,Linux
$ busybox awk -f test.awk
test,,test,
(Brian Kernighan(at)이 관리하며 bwk-awk
Solaris나 FreeBSD 등을 기반으로 한 awk 구현과 유사하게 작동합니다.)k
awk
nawk
awk
"uname"
busybox awk를 사용하여 파일과 명령을 동시에 사용할 수 없는 방법 과 닫히지 않는 getline
방법에 대해 알아보세요.close("uname")
uname
문서존재하다 gawk
.
따라서 동일한 이름을 가진 파일과 명령을 동시에 사용하지 않는 것이 가장 좋습니다. "\n"
시작이나 끝 부분에 추가 할 수 있습니다 .주문하다와 연관될 가능성을 낮추는 것문서.
좋다:
awk 'BEGIN {getline foo < $ENVIRON["FILE"]; "uname\n" | getline system}'
$FILE
만약 그렇다면, 이 문제는 피할 수 있을 것입니다 uname
( $FILE
그럴 경우는 아니지만 uname<newline>
가능성은 낮습니다).
답변2
흥미로운 점은 이 구조에서 awk
이전에 이 호출을 수행했다는 사실을 기억하고 다시 수행하지 않기 때문에 데이터가 readline
.
우리는 이것을 함으로써 이것을 볼 수 있습니다strace -f -o xxx awk ....
추적을 통해 다음을 확인할 수 있습니다.
3401 execve("/bin/date", ["date", "+%Y-%m-%d", "-d", "3 days ago"], [/* 50 vars */]) = 0
3403 execve("/bin/date", ["date", "+%Y-%m-%d", "-d", "46 years ago "], [/* 50 vars */]) = 0
3405 execve("/bin/date", ["date", "+%Y-%m-%d", "-d", "08:47:53"], [/* 50 vars */]) = 0
3407 execve("/bin/date", ["date", "+%Y-%m-%d", "-d", "1 year ago 46 weeks ago "], [/* 50 vars */]) = 0
3409 execve("/bin/date", ["date", "+%Y-%m-%d", "-d", "13 weeks ago 4 days ago "], [/* 50 vars */]) = 0
따라서 각 고유 날짜는 한 번만 통과되지만 다시는 통과되지 않습니다. 이는 CentOS 7 및 Debian의 GNU awk에서 발생하므로 mawk
이는 예상된 동작인 것 같습니다.
간단한 방법은 각 줄을 고유하게 만드는 것입니다. 예를 들어 줄 번호와 함께 주석을 추가합니다.
cmd2="date \"+'%Y-%m-%d'\" -d \""$2 "\" ; # " NR
생성된 코드는 다음과 같습니다.
awk -F, -v OFS="," '{cmd2="date \"+'%Y-%m-%d'\" -d \""$2 "\" ; # " NR ;
cmd2|getline d2;
print cmd2,d2}' x
date "+%Y-%m-%d" -d "3 days ago" ; # 1,2016-08-18
date "+%Y-%m-%d" -d "46 years ago " ; # 2,1970-08-21
date "+%Y-%m-%d" -d "46 years ago " ; # 3,1970-08-21
date "+%Y-%m-%d" -d "46 years ago " ; # 4,1970-08-21
date "+%Y-%m-%d" -d "08:47:53" ; # 5,2016-08-21
date "+%Y-%m-%d" -d "1 year ago 46 weeks ago " ; # 6,2014-10-03
date "+%Y-%m-%d" -d "46 years ago " ; # 7,1970-08-21
date "+%Y-%m-%d" -d "13 weeks ago 4 days ago " ; # 8,2016-05-18
date "+%Y-%m-%d" -d "46 years ago " ; # 9,1970-08-21
date "+%Y-%m-%d" -d "46 years ago " ; # 10,1970-08-21
date "+%Y-%m-%d" -d "46 years ago " ; # 11,1970-08-21
date "+%Y-%m-%d" -d "46 years ago " ; # 12,1970-08-21
date "+%Y-%m-%d" -d "46 years ago " ; # 13,1970-08-21
date "+%Y-%m-%d" -d "46 years ago " ; # 14,1970-08-21
더 복잡한 해결책은 결과를 배열에 캐시하고 date
이전에 이 날짜를 본 적이 없는 경우에만 호출하는 것입니다.
답변3
2열과 3열의 상대 날짜를 실제 날짜로 바꿉니다.
awk -F, '{for(i=2;i<4;i++){"date -I -d \""$i"\"" | getline a; $i=a}}1' OFS=, tst
직접적으로 작동하지 않는다는 사실에 놀랐습니다 getline $i
. 두 필드 중 하나를 변경하거나 아무것도 변경하지 않습니다. 따라서 a
정의된 사용자 함수에 추가 변수를 포함 해야 합니다 .
awk -F, '
function cmd2(date){
"date -I -d \""date"\"" | getline a
return a
}
{
$2=cmd2($2)
$3=cmd2($3)
print
}' OFS=, tst
그러나 함수가 지역 변수로 정의되면 cmd2(date, a)
위와 동일한 동작을 나타냅니다.
동질적인 라인 작업을 쉽게 완료할 수 있습니다.GNU sed
tr ',' '\n' tst |
sed '1~3!{s/^/date -I -d "/;s/$/"/e;}' |
paste -sd ',,\n'