查找目录分支中某些文件的总大小


140

假设有一个映像存储目录,例如,./photos/john_doe其中有多个子目录,其中驻留了许多特定文件(例如*.jpg)。如何计算john_doe分支下面这些文件的摘要大小?

我试过了du -hs ./photos/john_doe/*/*.jpg,但这只显示单个文件。此外,此操作仅跟踪john_doe目录的第一个嵌套级别,例如john_doe/june/,但会跳过john_doe/june/outrageous/

那么,如何遍历整个分支,求和某些文件的大小呢?

Answers:


183
find ./photos/john_doe -type f -name '*.jpg' -exec du -ch {} + | grep total$

如果du由于文件列表很长而需要多次调用,那么将报告多个总计,并且需要对其进行汇总。


7
查找-iname'文件*'-exec du -cb {} + | grep total $ | 切-f1 | 粘贴-sd +-| bc#总计字节大小
MichalČizmazia15年

3
如果您的系统使用其他语言运行,则需要将total $更改为波兰语中的razem $之类的其他单词。
Zbyszek

1
您可以LC_ALL=POSIX像这样在总grep中添加前缀,例如:LC_ALL=POSIX find ./photos/john_doe -type f -name '*.jpg' -exec du -ch {} + | grep total$
Sven 2016年

2
如果您没有使用-name,则将grep更改为,grep -P "\ttotal$"否则它将捕获所有以“ total”结尾的文件。
thdoan

3
@MichalČizmazia某些外壳程序(例如Windows的Git Bash)不附带bc,因此这里是一种更可移植的解决方案:find -name '*.jpg' -type f -exec du -bc {} + | grep total$ | cut -f1 | awk '{ total += $1 }; END { print total }'
thdoan

50
du -ch public_html/images/*.jpg | grep total
20M total

给我.jpg该目录中文件的总使用量。

要处理多个目录,您可能必须以find某种方式将其组合。

您可能会发现du命令示例很有用(还包括find


2
这不会遍历基础目录吗?
mbaitoff 2012年

这种类型比接受的解决方案更容易键入,但是只有一半正确,它不会在子目录中包含图像。很高兴知道所有文件是否都在一个目录中。
gbmhunter

@gbmhunter我认为,如果将-R参数添加到-ch,您还将获得子目录,因为它以递归方式遍历目录树。我目前不在电脑上尝试进行确认。
列文

1
-Rman7.org/linux/man-pages/man1/du.1.html上看不到任何选项。而且我不认为递归选项在这种情况下会有所帮助,因为外壳程序会在将参数传递给之前进行全局扩展du
gbmhunter

22

首先,您需要两件事:

  • -c选项du,告诉它产生总计;
  • 任一**激活指令)或find例如)或遍历子目录。
du -ch -- **/*.jpg | tail -n 1

很好的答复。比使用find更简单(只要*或**匹配目录结构)
Andre de Miranda

它也可以处理很长的文件列表,而使用find可能会返回错误的结果。
埃里克·富妮

bash括号扩展也允许测量多组通配符。du -ch -- ./{dir1,dir2}/*.jpgdu -ch -- ./{prefix1*,prefix2*}.jpg
J.Money

@EricFournie但是Argument list too long处理大约300k文本文件时出现错误。
xtluo

可以使用来检查命令的最大参数数量(在这种情况下,是通配符扩展返回的文件名)getconf ARG_MAX。如果您有更多文件,则需要使用for循环逐个或逐批处理文件。
埃里克·富尼

17

最终答案是:

{ find <DIR> -type f -name "*.<EXT>" -printf "%s+"; echo 0; } | bc

甚至更快的版本,不受RAM的限制,但这需要具有bignum支持的GNU AWK:

find <DIR> -type f -name "*.<EXT>" -printf "%s\n" | gawk -M '{t+=$1}END{print t}'

此版本具有以下功能:

  • find指定所需文件的所有功能
  • 支持数百万个文件
    • 这里的其他答案受参数列表的最大长度限制
  • 仅生成3个简单过程,并以最小的管道吞吐量
    • 这里有许多答案会生成C + N进程,其中C是一些常数,而N是文件数
  • 不用理会字符串操作
    • 这个版本没有做任何grepping或正则表达式
    • 好,find对文件名进行简单的通配符匹配
  • 任选地格式化的总和为人类可读的形式(例如5.5K176.7M,...)
    • 做那个附加 | numfmt --to=si

我喜欢这个答案的简单性,尽管它仅对我有用,在我在开括号之后和闭括号之前引入空格时才有用。我确实想知道它是否真的会支持'infiinte'数量的文件:)
andyb

1
@andyb感谢您的反馈,BASH中确实需要在括号周围添加空格,我使用的是ZSH,所以我没有注意到。和文件的数量由系统上的可用RAM为BC的内存使用量的限制增长缓慢作为数字流。
扬Chren - rindeal

8

到现在为止给出的答案都没有考虑到从find到du传递的文件列表可能很长,以至于find会自动将列表拆分成多个块,从而导致多次出现total

您可以grep total手动(locale!)进行总结,也可以使用其他命令。AFAIK只有两种方法可以找到由find找到的所有文件的总和(以千字节为单位):
find . -type f -iname '*.jpg' -print0 | xargs -r0 du -a| awk '{sum+=$1} END {print sum}'

说明
find . -type f -iname '*.jpg' -print0:查找所有带有jpg扩展名的文件,而不管大小写如何(例如* .jpg,*。JPG,*。Jpg ...)并输出(以Null结尾)。
xargs -r0 du -a:-r:即使没有传递任何参数,Xargs也会调用该命令,这-r可以防止。-0表示以null终止的字符串(不以换行符终止)。
awk '{sum+=$1} END {print sum}':总结上一条命令输出的文件大小

作为参考,另一种方式是
find . -type f -iname '*.jpg' -print0 | du -c --files0-from=-


附加提示:在具有23428个文件(22323是图像)的HDD上,第一种方法运行1秒,而第二种方法运行3.8秒。
1

请注意,两者均假定为GNU系统。第一个假设文件名不包含换行符。
斯特凡Chazelas

我敢打赌,du --file0-from花了更长的时间,因为您先运行了它(缓存效果)。
斯特凡Chazelas

使用xargsdu -a可能会运行多个,因此,如果存在硬链接,则可能会有差异。
斯特凡Chazelas

3

如果文件列表太大而不能传递给du -cGNU系统上的单个调用,则可以执行以下操作:

find . -iname '*.jpg' -type f -printf '%b\t%D:%i\n' |
  sort -u | cut -f1 | paste -sd+ - | bc

(大小以512字节块的数量表示)。像du它只计算一次硬链接。如果您不关心硬链接,则可以将其简化为:

(printf 0; find . -iname '*.jpg' -type f -printf +%b) | bc

如果要使用大小而不是磁盘使用量,请替换%b%s。大小将以字节表示。


-bash: bc: command not foundCentos-Linux 2.6.32-431.el6.x86_64
yeya

@yeya,听起来您的CentOS部署已损坏。bc是非可选的POSIX命令。
斯特凡Chazelas

1

到目前为止提到的解决方案效率低下(exec成本很高),并且如果文件列表很长或者它们不能在Mac OS X上运行,则需要进行额外的手动工作才能总结。以下解决方案非常快,可以在任何系统上使用,并且产生以GB为单位的总答案(如果要以MB为单位,则删除/ 1024): find . -iname "*.jpg" -ls |perl -lane '$t += $F[6]; print $t/1024/1024/1024 . " GB"'


既不是标准的-iname也不-ls是便携式的,因此它也不能在任何系统上运行。如果有包含换行符的文件名或符号链接目标,它也将无法正常工作。
斯特凡Chazelas

还要注意,它给出的是文件大小的总和,而不是磁盘的使用情况。对于符号链接,它给出符号链接的大小,而不是它们指向的文件。
斯特凡Chazelas

1

像Zbyszek在他的评论中已经指出的那样,改进SHW的好答案以使其能够与任何语言环境一起使用。

LC_ALL=C find ./photos/john_doe -type f -name '*.jpg' -exec du -ch {} + | grep total$

1

du自然会遍历目录层次结构,而awk可以执行过滤,因此如下所示就足够了:

du -ak | awk 'BEGIN {sum=0} /\.jpg$/ {sum+=$1} END {print sum}'

这在没有GNU的情况下有效。


1
这更昂贵,因为它需要stat调用与搜索到的模式不对应的文件。
Law

仅此解决方案可在我的Mac上使用。
马提亚斯M
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.