考虑位于以下位置的 R 源代码存储库:https://cloud.r-project.org/src/base/R-3/R-3.4.4.tar.gz。我将存储库解压缩到一个文件夹中。现在,我想知道目录中有多少行。所以,我尝试了以下命令:
find . -type f -exec wc -l {} \+
产生 394968 但如果我尝试以下命令:
find . -type f -exec cat {} \+ | wc -l
它产生 1848857!
为什么这两个看似相似的命令操作会find
产生如此截然不同的结果?并且,查找行数的正确方法是什么,最好使用命令行实用程序而不是编写小工具脚本?
答案1
您提到的第一个命令find . -type f -exec wc -l {} +
实际上是说“运行wc -l
尽可能多的文件,直到所有文件都被处理”。这可以运行wc
多次!
另一方面,find . -type f -exec cat {} + | wc -l
可以运行
cat
多次,但只会运行wc
一次。 (更详细地说,这是因为在这种情况下cat
被调用find
,它可以并且确实决定运行它,无论它想要多少次,而管道字符之后的部分,wc -l
超出了 的范围find
,因此由您运行外壳,只需一次。)
你说第一个命令“产生 394968”,但事实并非如此;在我的系统上,其输出以以下内容结尾:
(Many more lines elided...)
23 ./po/Makefile.win
64 ./po/README
1 ./VERSION-NICK
97 ./README
258450 total
然而,通过添加grep total
,我们可以看到它wc
实际上运行了两次:
$ find . -type f -exec wc -l {} + | grep total
1590407 total
258450 total
事实上,1590407 加 258450 就是 1848857,这与第二条命令一致。
模糊地暗示了为什么在该命令的版本wc
中运行多次的解释find -exec wc +
查找手册页:
-exec command {} +
此
-exec
操作的变体对选定的文件运行指定的命令,但命令行是通过在末尾附加每个选定的文件名来构建的;该命令的调用总数将远小于匹配的文件数。命令行的构建方式与xargs
构建其命令行的方式大致相同。
请注意这表示“远少于……”而不是“仅一次”。这
xargs 的文档提示--max-chars
如果用户未设置其选项,则会自动设置:
--max-chars=max-chars
-s max-chars
最多使用
max-chars
每个命令行的字符数,包括命令和初始参数以及参数字符串末尾的终止空值。最大允许值取决于系统,计算方式为 exec 的参数长度限制减去环境大小,减去 2048 字节的余量。如果该值大于128KiB,则使用128Kib作为默认值;否则,默认值为最大值。
这限制了一次调用可以传递的文件名数量wc
,这解释了为什么对于大量文件,wc
会发生多次调用,每个调用都在输入的一个分区上进行操作。