我经常使用 awk 来解析日志;我从未见过这样的事情:我有六个包含多行的文件;我想要包含“100”的内容,并选择要打印的列
me:~/tmp> grep 100 *.dl.tst
输出我所期望的:
100 139M 100 139M 0 0 6376k 0 0:00:22 0:00:22 --:--:-- 6539k
100 139M 100 139M 0 0 6677k 0 0:00:21 0:00:21 --:--:-- 6579k
100 139M 100 139M 0 0 6022k 0 0:00:23 0:00:23 --:--:-- 6093k
100 139M 100 139M 0 0 13.9M 0 0:00:10 0:00:10 --:--:-- 14.3M
100 139M 100 139M 0 0 14.3M 0 0:00:09 0:00:09 --:--:-- 14.7M
100 139M 100 139M 0 0 13.2M 0 0:00:10 0:00:10 --:--:-- 13.3M
正如:
me:~/tmp> grep 100 *.dl.tst|awk '{print$0}'
100 139M 100 139M 0 0 6376k 0 0:00:22 0:00:22 --:--:-- 6539k
100 139M 100 139M 0 0 6677k 0 0:00:21 0:00:21 --:--:-- 6579k
100 139M 100 139M 0 0 6022k 0 0:00:23 0:00:23 --:--:-- 6093k
100 139M 100 139M 0 0 13.9M 0 0:00:10 0:00:10 --:--:-- 14.3M
100 139M 100 139M 0 0 14.3M 0 0:00:09 0:00:09 --:--:-- 14.7M
100 139M 100 139M 0 0 13.2M 0 0:00:10 0:00:10 --:--:-- 13.3M
那么为什么会$1
变成文件名:
me:~/tmp> grep 100 *.dl.tst|awk '{print$1}'
shpr002.20201124_141036.dl.tst:
shpr003.20201124_141036.dl.tst:
shpr004.20201124_141036.dl.tst:
hipr002.20201124_141036.dl.tst:
hipr003.20201124_141036.dl.tst:
hipr004.20201124_141036.dl.tst:
和$2
:
me:~/tmp> grep 100 *.dl.tst|awk '{print$2}'
0
0
0
0
0
0
我注销并重新登录,以防我的 shell (bash) 被搞砸了;没有改变...我做错了什么?
输出grep 100 *.dl.tst | awk '{print$1}' | head -n1 | od -c
(一些字母字符已被替换x
;上面的列表已被编辑/混淆)
0000000 x s h p r 0 0 2 x x x . x x x .
0000020 x x x x . c o m . 2 0 2 0 - 1 1
0000040 - 2 4 _ 1 4 1 0 3 6 . d l . t s
0000060 t : \r \n
0000064
答案1
这些文件包含下载文件的输出curl
,并curl
在下载期间通过输出回车符(通常表示为\r
,在许多上下文中用于生成回车符的转义符)来更新其进度信息,这会导致光标返回到文件的开头。线。
当您运行时grep 100 *.dl.tst
,输出的每一行都以文件名开头,但随后进行多次更新,将光标返回到行的开头,因此您看不到文件名 - 它会被后续输出覆盖。更详细地说,输出看起来像
shpr002.20201124_141036.dl.tst:
后面跟着一个回车符,后面跟着第一个进度输出curl
,
0 0 0 0 0 0 0 0 --:--:-- --:--:-- --:--:-- 0
然后是回车符,依此类推,直到百分比达到 100。因为所有这些都只用回车符分隔,而不是换行符,所以它算作一行,并且grep
与整个行匹配。
同样的效果解释了 的输出grep 100 *.dl.tst|awk '{print$0}'
。
当您要求 AWK 输出 时$1
,它会输出第一个字段,现在您可以看到它:它包含文件名、冒号、回车符,就是这样 -curl
的输出的开头然后以空格开头(为百分比计数留出空间),它是字段分隔符。当您要求它输出 时$2
,它会输出第二个字段,即第一个百分比计数0
:
shpr002.20201124_141036.dl.tst:\r 0 0 0 0 0 0 0 0 --:--:-- --:--:-- --:--:-- 0
<-- Field 1 --> ! ! ! ! ...
$2 $3 $4 $5 ...
答案2
致力于斯蒂芬对问题的描述,使输出更易于处理的一个简单方法是将所有回车符转换为换行符,将curl的进度报告留下为一堆单独的行,然后您可以将其用于awk
:
$ for f in *.dl; do < "$f" tr '\r' '\n' | awk '$1 == "100" {print $0}' ; done
100 720k 100 720k 0 0 22.5M 0 --:--:-- --:--:-- --:--:-- 22.7M
100 23.6M 100 23.6M 0 0 372M 0 --:--:-- --:--:-- --:--:-- 369M
(不过,如果curl将其打印的百分比四舍五入到最接近的整数而不是向下舍入,那么大文件可能会100
在第一列中显示多行。)
另一方面,如果知道文件只包含curl 的输出,那么我们不妨只选择最后一行而不是查看内容:
$ for f in *.dl; do < "$f" tr '\r' '\n' | tail -n1 ; done
100 720k 100 720k 0 0 22.5M 0 --:--:-- --:--:-- --:--:-- 22.7M
100 23.6M 100 23.6M 0 0 372M 0 --:--:-- --:--:-- --:--:-- 369M