インターフェイスの最後の入力と出力を表示するCiscoスイッチの出力を便利な形式に変換できるスクリプトを作成しようとしています。これは、たとえば、過去6ヶ月間、どのインターフェイスが使用されていないかを知ることができるようにするためです。シスコでは、インターフェイスへの最後の入力が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も指摘したように、入力ファイルの3行だけで問題はありませんでした。テストされていないシナリオを投稿して申し訳ありません。
答え1
これを行うとき:
cmd = "some command"
cmd | getline d2
cmd | getline d2
のawk
最初のものはgetline
出力の最初の行(レコード)を取得し、2番目は2番目の行を取得します。出力の終わりに達するとゼロが返されます。cmd
cmd
getline
getline
あなたの場合、cmd = "date -d \"46 years ago\""
コマンドは1行だけを出力するので、最初のコマンドはその行と正数をgetline
返しますが、2番目のコマンドは到着するので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'