【问题标题】:Apply awk command to all files in a directory将 awk 命令应用于目录中的所有文件
【发布时间】:2021-06-17 15:42:37
【问题描述】:

我是 awk 的新手,我想对目录中的所有文件应用一个简单的 awk 命令,并分别获取每个文件的结果。 这些文件是制表符分隔的,我只需要对第 11 列中的每个值求和,然后为每个文件分别打印结果。我尝试了以下代码,但它不起作用。

for i in *;
do
awk -F '\t' '{sum += $11} END {print sum} "$i"'
done

谢谢!

【问题讨论】:

    标签: awk


    【解决方案1】:

    你可以使用这个gnu awk:

    awk -F '\t' '{sum += $11} ENDFILE {print FILENAME ":", sum; sum=0}' *
    

    ENDFILE 块将在我们打印文件名和总和的每个文件的处理结束时运行。


    如果你没有gnu awk,那么使用这个:

    awk -F '\t' 'FNR==1 {if (sum) print fn ":", sum; sum=0; fn=FILENAME} 
    {sum += $11} END {print fn ":", sum}' *
    

    【讨论】:

    • @PaulaO:你发现这个答案有什么问题吗?
    【解决方案2】:

    您的 shell 引用中似乎有一个简单的错字;这应该工作:

    for f in *; do awk -F '\t' '{sum += $11} END {print sum}' -- "$f"; done
    

    -- 仅用于防止其中一个以连字符开头的文件名;一个名为i 的变量通常按照旧的 Fortran 约定是整数,因此将一个变量用于字符串有点不合常理);或替代

    ls | while read -r f; do awk -F '\t' '{sum += $11} END {print sum}' -- "$f"; done
    

    如果您想避免达到命令行长度限制的风险(在当前系统上很大但有限),但如果您的文件名中有换行符,这会中断(为什么?!..)。

    如果您想在一次 Awk 调用中完成所有操作,您可以使用 FNR(文件内的记录数)和 FILENAME 来跟踪文件:

    awk -F '\t' 'FNR==1 {if (f) print sum; sum = 0; f = FILENAME} END {print sum} {sum += $11}' -- *
    

    或者(可以调用 awk 一次或多次)

    ls | xargs awk -F '\t' 'FNR==1 {if (f) print sum; sum = 0; f = FILENAME} END {print sum} {sum += $11}' --
    

    具有与上述相同的警告。

    您可以通过放弃 POSIX 并使用 GNUisms 来防止文件名中的换行符,它使用 NUL(文件名中被禁止)而不是换行符(不被禁止)分隔项目,但除非您的脚本要在真正敌对的环境中运行,否则它可能不值得。

    【讨论】:

      最近更新 更多