我有一个简单的 bash 脚本:
#!/bin/bash
enp="$(ip route | grep "192.168.1.1" | cut -d' ' -f 3)"
while true; do
vnstat -l -i "$enp" --style 4 --json | awk '{ print strftime("[%d/%b/%Y:%H:%M:%S]"), $0 }' >> raw/caching_server_network.json
printf -- '-%.0s' {1..100}; echo "" >> raw/caching_server_network.json
sleep 10
done
目前,此脚本将 strftime 附加到每个 vnstat 输出的开头,并且 strftime 在每次调用时都会更新。输出:
[04/Jan/2022:13:31:17] {"index":1012,"seconds":2024,"rx":{"ratestring":"13.59 Mbit/s","bytespersecond":1698943,"packetspersecond":15220,"bytes":3397887,"packets":30441,"totalbytes":29895276777,"totalpackets":43496469},"tx":{"ratestring":"2.81 Gbit/s","bytespersecond":350918926,"packetspersecond":233842,"bytes":701837853,"packets":467685,"totalbytes":518923724379,"totalpackets":354639132}}
[04/Jan/2022:13:31:41] {"index":1013,"seconds":2026,"rx":{"ratestring":"206.68 Mbit/s","bytespersecond":25834765,"packetspersecond":31840,"bytes":51669531,"packets":63681,"totalbytes":29946946308,"totalpackets":43560150},"tx":{"ratestring":"3.15 Gbit/s","bytespersecond":394123782,"packetspersecond":269030,"bytes":788247565,"packets":538060,"totalbytes":519711971944,"totalpackets":355177192}}
我想做的是让日期时间字符串包含毫秒。但我面临一个问题,日期输出不再更新。每次调用只是将相同的时间添加到字符串中。
我已经尝试过以下方法:
#!/bin/bash
enp="$(ip route | grep "192.168.1.1" | cut -d' ' -f 3)"
while true; do
vnstat -l -i "$enp" --style 4 --json | awk '{ print "'"$(date +%F:%T.%3N)"'", $0 }' >> raw/caching_server_network.json
printf -- '-%.0s' {1..100}; echo "" >> raw/caching_server_network.json
sleep 10
done
输出:
04/Jan/2022:13:30:11.743 {"index":975,"seconds":1950,"rx":{"ratestring":"73.04 Mbit/s","bytespersecond":9130121,"packetspersecond":25590,"bytes":18260242,"packets":51181,"totalbytes":29368713172,"totalpackets":42315654},"tx":{"ratestring":"3.90 Gbit/s","bytespersecond":486961964,"packetspersecond":326200,"bytes":973923928,"packets":652400,"totalbytes":498158299423,"totalpackets":340676257}}
04/Jan/2022:13:30:11.743 {"index":976,"seconds":1952,"rx":{"ratestring":"12.23 Mbit/s","bytespersecond":1529119,"packetspersecond":17962,"bytes":3058239,"packets":35924,"totalbytes":29371771411,"totalpackets":42351578},"tx":{"ratestring":"4.18 Gbit/s","bytespersecond":522336815,"packetspersecond":346742,"bytes":1044673631,"packets":693484,"totalbytes":499202973054,"totalpackets":341369741}}
请注意上面输出中两行的日期时间是如何相同的。在使用日期调用时,如何获取每次 vnstat 调用更新的日期?
答案1
每次调用 都会更改时间vnstat
,但如果vnstat
输出多行,则所有行都会收到相同的时间。这是因为 shell 运行date
并将其输出插入到 的参数中awk
。
要获取每行的新时间戳,您需要date
从内部调用awk
.由于我vnstat
的机器上没有,我创建了一个更简单的示例:
#! /bin/bash
while true; do
for i in {1..3} ; do
echo $i
sleep .1
done | awk '{ system("date +%F:%T.%3N\\ | tr -d \\\\n"); print $0 }'
printf -- '-%.0s' {1..80}; echo ""
sleep 1
done
删除tr
时间戳后面的换行符。
答案2
我不会使用 shell 循环并在每次迭代中调用一个awk
, date
,sleep
实用程序(或更糟糕的是,每次调用命令的每一行输出),我会在可以在内部完成所有这些操作的方式中完成整个操作,例如perl
:
perl -MPOSIX -MTime::HiRes=gettimeofday -e '
while (1) {
open CMD, "-|", @ARGV;
while (<CMD>) {
my ($s,$us) = gettimeofday;
printf "%s.%03d %s", strftime("%F:%T", localtime$s), $us/1000, $_
}
print "-" x 100 . "\n";
sleep 10;
}' vnstat -l -i "$enp" --style 4 --json >> file.log
或者在zsh
:
zmodload zsh/zselect
ts_format='%D{%F:%T.%3.}'
sep=${(l[80][-])}
while true; do
vnstat -l -i "$enp" --style 4 --json |
while IFS= read -r line; do
print -r ${(%)ts_format} $line
done
echo $sep
zselect -t 1000 # cs
done >> file.log