使用find、wc和sed命令来统计行数。

30

我试图使用sed命令计算基于特定扩展名的所有行数。

find -name '*.m' -exec wc -l {} \; | sed ...
我试图做以下操作,请问如何在这行代码中使用sed获取总数。
8个回答

57

您也可以使用 wc 命令获得漂亮的格式化输出:

wc `find -name '*.m'`

9
为避免与目录名匹配的情况,请在命令中添加“-type f”:wc $(find -type f -name '*.m')。该命令的作用是找到所有扩展名为“.m”的文件,并将它们传递给“wc”命令计算它们的行数、单词数和字符数。 - Dennis Williamson
2
wc $(find -name '*.m') 更美观。 - jason
任何包含空格或其他 shell metacharacters 的文件名都会导致程序出错。 - tripleee
@tripleee,你如何在这种情况下恢复空格?我目前遇到了这个问题。 - Working dollar
@Workingdollar https://mywiki.wooledge.org/BashFAQ/020 和/或本页面上的其他答案。 - tripleee
@tripleee 感谢您提供的文档。我发现这个命令对我最有效 find . -name '*.m' -exec wc {} \; - Working dollar

19

这里大多数答案无法很好地处理大量文件。一些解决方案在单个命令行调用的文件名列表太长时会出现错误,而其他解决方案效率低下,因为-exec会为每个文件启动一个新进程。我认为一个强大且高效的解决方案应该是:

find . -type f -name "*.m" -print0 | xargs -0 cat | wc -l

这种方式使用cat是可以的,因为它的输出被直接管道到wc中,所以每次只会在内存中保留少量文件内容。如果有太多的文件需要进行单个cat调用,则会多次调用cat,但所有输出仍将被输送到单个wc进程中。


2
或者使用标准/便携式形式:find . -type f -name '*.m' -exec cat {} + | wc -l - Stephane Chazelas
如何修改此代码以打印出每个文件的总行数和文件名? - loretoparisi
1
@loretoparisi 然后,可以轻松地运行-exec wc -l {} +而不是-print0 | xargs ...。使用+-exec可能会运行多个wc -l实例,然后您需要对每次运行的总计进行求和以获得总体总数。或者,如果您不关心总数,请使用grep -v删除那些行;或者,使用-exec wc -l {} \;在每个文件上运行单独的wc实例,但处理成本略高。 - tripleee

6
您可以通过单个 wc 实例将所有文件连接起来,以获得总行数:

cat

find . -name '*.m' -exec cat {} \; | wc -l

5

在现代GNU平台上,wc和find命令可以使用-print0和-files0-from参数组合成一个命令,该命令可以计算文件中的行数,并在末尾显示总数。示例:

find . -name '*.c' -type f -print0 | wc -l --files0-from=-

4

您也可以使用sed来计算行数,而不是使用wc:

 find . -name '*.m' -exec sed -n '$=' {} \;

其中'$='是一个“特殊变量”,用于计算行数

编辑

您还可以尝试类似sloccount的工具。


找到所有扩展名为 .m 的文件,并执行 sed -n 'where $=' 命令。 - Berlin Brown
那不是总数,它们需要加在一起。 - Berlin Brown
好的,我最终得到了这个。$ find . -name '*.m' -exec sed -n '$=' {} ; | sum - 22696 1 - Berlin Brown
3
“$=”是一个特殊变量,用于计算输入的行数。开个玩笑吧!"$="代表一个地址和一个命令。"$"代表最后一行,“=”命令表示当前行号,结合"-n"参数,该命令可以抑制模式空间的输出。结果就是它__计算__输入行的数量。 - potong
@dfa 谢谢。如何在计数之前打印文件名? - loretoparisi

3

嗯,如果您有许多文件,尤其是大文件,则使用cat解决方案可能会出现问题。

第二种解决方案只提供每个文件的行数,无法给出总行数,我已经测试过了。

我更喜欢像这样的解决方案:

find . -name '*.m' | xargs wc -l | tail -1

这将快速完成任务,无论您有多少个及多大的文件。

如果有太多的文件需要在单个命令行中处理,xargs 将对它们进行分块处理,这将只给出最后一个块的总数。 - Daniel James

1

sed 不是计数的合适工具。请使用 awk 代替:

find . -name '*.m' -exec awk '{print NR}' {} +

使用 + 而不是 \; 强制 find 每找到 N 个文件就调用 awk(就像 xargs 一样)。


有趣的是,我实际上想说的是awk。 - Berlin Brown

1

对于大型目录,我们应该使用:

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

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

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接