awk 中的命令替换

awk 中的命令替换

有没有办法在 AWK 中执行命令替换,并能够使用$nAWK 的表示法引用替换命令中的字段?

例如

find | awk '/txt$/ {nl = $(wc -l $NF); print nl}'

我希望上面的内容能够打印每个.txt文件中的行数。相反,它实际上返回与以下内容相同的输出:

find | awk '/txt$/ {print}'

问题一:有没有办法在 awk 中执行命令替换?

问题2:为什么上面的第一个咒语默默地失败并且只是打印文件名?

请注意,上述内容仅作为示例提供。我不是问如何通过其他方式打印每个文件的行数。例如通过for f in $(find -iname \*.txt); do wc -l $f; done

问题具体是关于如何在 AWK 程序中利用命令替换。

答案1

首先,免责声明:请不要解析 的输出find 下面的代码仅用于说明如何将命令替换合并到 Awk 脚本中,以便命令可以对 Awk 的输入片段进行操作。

实际上wc -l对找到的每个文件进行行计数( ) find(这是示例用例),只需使用:

 find . -type f -name '*txt' -exec wc -l {} +

但是,要回答您提出的问题:

Q1

回答你的问题1:

Q1:有没有办法在 awk 中执行命令替换?

当然有一种方法,来自man awk

命令 | getline [var] 运行命令,将输出通过管道传输到 $0 或 var(如上所述)和 RT。

所以(看引用!!):

find . | awk '/txt$/{"wc -l <\"" $NF "\"|cut -f1" | getline(nl); print(nl)}'

请注意,构建的字符串以及因此执行的命令是

wc -l <file

以避免打印wc.

好吧,我避免了该命令所需的文件“关闭”(对于几个文件来说是安全的,但技术上不正确)。你实际上需要做:

find . | awk '/txt$/{
                       comm="wc -l <\"" $NF "\" | cut -f1"
                       comm | getline nl;
                       close (comm);
                       print nl 
                    }'

这也适用于较旧的 awk 版本。请记住避免使用
打印点,这会使代码失败,因为点是目录,而 wc 不能使用它。.find .

或者,避免使用点值:

find . | awk '/txt$/ && $NF!="." {  comm="wc -l <\"" $NF "\" | cut -f1"
                                    comm | getline nl;
                                    close (comm);
                                    print nl 
                                 }'

您可以将其转换为单行代码,但我认为它看起来很丑陋。

Q2

至于你的第二个问题:

问题 2:为什么上面的第一个咒语会默默地失败,而只是打印文件名?

因为 awk 不能正确解析 shell 命令。它将命令理解为:

nl = $(wc -l $NF)
nl --> variable
$ --> pointer to a field
wc --> variable (that has zero value here)
-  --> minus sign
l  --> variable (that has a null string)
$  --> Pointer to a field
NF --> Last field

然后,l $NF变成 null 和 the 的串联文本在 las 字段(文件名)内。此类文本作为数值变量的扩展是数值 0

对于 awk 来说,它变成:

nl = $( wc -l $NF)
nl = $ ( 0 - 0 )

这变成了$0整行输入,(对于上面的简单查找)只是文件名。

因此,以上所有内容只会打印文件名(好吧,从技术上讲,是整行)。

答案2

使用"weak quotes"而不是在脚本'strong quotes'内进行子 shell 扩展awk,但在您的示例中这样做并不是一个特别有价值的实现。它看起来也非常丑陋:

$ awk "END { print \"$(echo hello)\"} " < /dev/null
hello

相关内容