为什么“find . -name *.txt | xargs du -hc”会给出多个总数?

10

我有一组大量目录,我试图计算数百个.txt文件的总大小。 我尝试了这个方法,它大多有效:

find . -name *.txt | xargs du -hc

但是我得到的不是最终的总数,而是好几个结果。我猜测这是由于管道每次只传递find输出的有限行数,而du则对每批数据进行操作。有没有办法解决这个问题?

谢谢! Alex


嗯,好的。我尝试了以下命令: find . -name *.txt | xargs -n 100000 du -hc 但这似乎不起作用 - 我得到更多小计,而不是更少。尝试使用以下命令: find . -name *.txt |xargs -L 1000 du -hc 也不太起作用。要么是“xargs:参数列表过长”,要么只对很少的文件进行操作。还有其他想法吗?谢谢! Alex - Alex
7个回答

12

使用--files0-from选项来计算du的大小如何?您需要适当生成以空字符结尾的文件输出:

find . -name "*txt" -exec echo -n -e {}"\0" \; | du -hc --files0-from=-

在我的系统上正常工作。


3
这对我有效,但我使用了find的-print0而不是执行echo的命令。 - tladuke
哦,我不知道有-print0选项。这样会更加简洁。谢谢! - Sbodd
1
-print0 从技术上讲不是 posix 标准(因为不是所有命令都能处理以 $'\0' 结尾的文件,这个原因非常奇怪)。尽管如此,大多数实现似乎已经扩展了该选项。 - Reinstate Monica Please

9
find . -print0 -iname '*.txt' | du --files0-from=-

如果您想搜索多个不同的扩展名,最好这样做:

find . -type f -print0 | grep -azZEi '\.(te?xt|rtf|docx?|wps)$' | du --files0-from=-

-exec echo {}"=0"; 更容易记住。等等,不对。嗯 -exec echo -n {}"\0" \;。不行吗?-exec echo $#&@*#(@!@#$@#!!!(好多了) - Stephen
你列出的第一种方式永远不会到达“-iname .txt”测试,如果你的工作目录中有“.txt”文件,那么glob“.txt”将在执行“find”之前扩展。 - Reinstate Monica Please
你说得对。感谢指出这个打字错误。我已经更正了。 - OmnipotentEntity

6
xargs程序将内容分成批处理,以考虑由于unix命令行的最大长度而产生的限制。它仍比逐个运行子命令更有效,但对于长列表输入,它将运行足够多次命令以使每次“运行”足够短,不会造成问题。
因此,您可能会看到每个“批次”中xargs需要运行一个输出行。
由于您可能会发现它有用/有趣,这里可以在线找到man页面:http://unixhelp.ed.ac.uk/CGI/man-cgi?xargs

还有一件事需要注意(这可能是您的帖子中的笔误或我的误解),即您未对“*.txt”进行转义/引用。也就是说,您有:

find . -name *.txt | xargs du -hc

你可能想要的地方

find . -name \*.txt | xargs du -hc

区别在于命令行可能会将 * 展开为与之匹配的文件名列表,而不是将 * 传递给 find,后者将使用它作为模式。

3

另一个简单的解决方案:

find . -name *.txt -print0 | xargs -0 du -hc

1
为了提高您的帖子质量,请说明您的帖子如何/为什么能解决问题。 - Mick MacCallum

1
一种替代方案是使用bash的for循环:
for i in `find . -name '*.txt'`; do du -hc $i | grep -v 'total'; done

这对于需要更多控制循环中发生的事情时非常有用。

0

xargs将其输入分成合理大小的块 - 您看到的是每个块的总计。请查看xargs的man页面以了解如何配置其处理输入的方式。


0
一个备选方案是使用awk:
find . -name "*.txt" -exec ls -lt {} \; | awk -F " " 'BEGIN { sum=0 } { sum+=$5 } END { print sum }'

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