awk 似乎很困惑 $1 是什么

awk 似乎很困惑 $1 是什么

我经常使用 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

相关内容