将“find”的输出通过管道传输到“xargs wc”会产生不合理的总数

将“find”的输出通过管道传输到“xargs wc”会产生不合理的总数

在一个包含数千个文件的项目中,我想比较总代码行数和仅在 PHP 中的代码行数(丢弃 CSS、JavaScript 等)。

当我跑步时

find . -type f | xargs wc -l

最后一行的总数是降低比当我跑步时

find -E . -regex '.+\.(php|inc)' -type f | xargs wc -l

考虑到第二个文件find列表必须比第一个文件列表更小(是第一个文件的严格子集) ,那么在第二种情况下find如何报告更高的总数?wc

答案1

xargs只能通过 最大参数字节的参数wc

在我的 Mac 上,ARG_MAX 小于整个项目文件的完整文件名和相对路径,因此在第一的命令,xargs将结果转储findwc 分两批,这wc意味着两个总计,周围有数千个文件名。但 ARG_MAX 恰好大于第二 find输出,因此第二个较小的 find all 显示在 wc全部的。

解决方法是使用这些命令,这样我就可以看到所有的总数,而不需要(无聊的)单独的文件计数行:

find . -type f | xargs wc -l | grep total
find -E . -regex '.+\.(php|inc)' -type f | xargs wc -l | grep total

然后手动将几行“总计”相加。

答案2

有很多方法可以做到这一点,但xargs都不是最好的。以下是一些:

  1. 最简单的方法是对cat找到的每个文件find进行计数。注意,这只在文件名中没有空格或奇怪字符时才有效:

    find . -type f | while read n; do cat $n; done | wc -l
    find -E . -regex '.+\.(php|inc)' -type f | while read n; do cat $n; done | wc -l 
    

    如果您的文件名可能包含奇怪的字符(斜杠、空格等),请改用以下方法:

    find . -type f | while IFS= read -r n; do cat $n; done | wc -l
    find -E . -regex '.+\.(php|inc)' -type f | while IFS= read -r n; do cat $n; done | wc -l 
    
  2. 更好的方法是使用 find 的-exec选项:

    find . -name "*.pep" -exec cat {} \; | wc
    find -E . -regex '.+\.(php|inc)' -type f -exec cat {} \; | wc
    

答案3

用于将输出awk的各个“总数”相加wc -l

(注意:wc -l返回换行符的数量,即没有最后一个字符的最后一个“行”将不被计算 - 就像或 的\n情况一样。)awksed

export LC_ALL=C
find . -type f -print0 | xargs -0 wc -l | 
    awk '/^ *[[:digit:]]+ total$/{ total+=$1 }END{print total}'


# xargs alternatives using: find ... -exec <wc|awk|sed> ... '{}' +
#man find | less -p '{} \+'

# wc
find . -type f -exec wc -l '{}' + 2>/dev/null | 
   awk '/^ *[[:digit:]]+ total$/{ total+=$1 }END{print total}'

# awk
find . -type f -exec awk 'END {print NR}' '{}' + 2>/dev/null | 
    awk '{ total+=$1 }END{print total}'

# sed
find . -type f -exec sed -n '$=' '{}' + 2>/dev/null | 
    awk '{ total+=$1 }END{print total}'

相关内容