xargs wc -l 报告两个总数

xargs wc -l reports two totals

我要计算目录/usr/local/lib/python3.5/dist-packages/pandas.

中的所有行
cd /usr/local/lib/python3.5/dist-packages/pandas
find  -name '*.*' |xargs  wc -l
536577 total

将两行写成一行。

 find  /usr/local/lib/python3.5/dist-packages/pandas  -name '*.*' |xargs wc -l    

bash输出两个total数,一个是495736,一个是40841

495736 + 40841 = 536577

为什么bash只给一个总536577在最下面如find -name '*.*' |xargs wc -l呢?

POSIX xargs spec. 说:

The generated command line length shall be the sum of the size in bytes of the utility name and each argument treated as strings, including a null byte terminator for each of these strings. The xargs utility shall limit the command line length such that when the command line is invoked, the combined argument and environment lists shall not exceed {ARG_MAX}-2048 bytes.

这意味着;在您的情况下,find 的输出不适合 ARG_MAX‒2048 字节,因此 xargs 将其聚合为 2 组并为每组调用 wc 一次。


以这条管道为例,在理想世界中它的输出应该是 1,但事实并非如此。

seq 1000000 | xargs echo | wc -l

seq 的输出是 6888896 字节。

$ seq 1000000 | wc -c
6888896

我的环境列表占用558个字节(忽略_是动态的,为了清楚起见,实现是否考虑了终止空指针)。

$ env | wc -c
558

ARG_MAX 在我的系统上是 131072 字节。

$ getconf ARG_MAX
131072

现在 xargs 有 131072-2048-558 = 128466 字节; echo加上空分隔符占用5个字节,所以还剩下一个space,共128461字节。因此我们可以说,xargs 将不得不调用 echo 6888896/128461 = ~54 次。让我们看看是不是这样:

$ seq 1000000 | xargs echo | wc -l
54

是的,是的。

您可以通过向管道添加 awk 位来多次处理 xargs 运行 命令:

find wherever -name "*.*" -type f -print0 | \
xargs -0 wc -l | \
awk ' == "total" { total +=  } END { print "Overall total", total } 1'

(假设 GNU findxargs 或其他分别理解 -print0-0 的实现;否则文件名中包含空格等可能会导致问题)。

GNU find 也许其他实现可以跳过 xargs,实际上:

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

与一次对多个文件使用 xargs 到 运行 wc 的效果相同。