如何获取实际目录大小(超出du)?


17

如何使用UNIX / Linux标准工具获取实际目录大小?

替代问题:如何获取du以显示实际目录大小(而不是磁盘使用情况)?

由于人们似乎对术语“大小”有不同的定义:我对“目录大小”的定义是该目录中所有常规文件的总和。

我不在乎目录inode的大小或文件在相应文件系统上占用的任何大小(块*块大小)。一个包含3个文件(每个1字节)的目录,其目录大小为3字节(根据我的定义)。

使用du计算目录大小似乎不可靠。
例如,mkdir foo && du -b foo报告“ 4096 foo”,而不是0字节的4096字节。对于非常大的目录,报告的目录大小du -hs可能相差100 GB(!)或更多(压缩文件系统)。

那么必须使用什么(工具/选项)来获得实际的目录大小?


在新位置中使用了什么文件系统xfs
谢尔盖·弗拉索夫


而且,如果您的新FS确实是XFS,则磁盘使用率的大大提高可能是由于积极的预分配,从而减少了文件碎片,但以磁盘使用为代价。
谢尔盖·弗拉索夫

Answers:


8

这是一个使用Unix标准工具(POSIX)显示人类可读目录大小的脚本。

#!/bin/sh
find ${1:-.} -type f -exec ls -lnq {} \+ | awk '
BEGIN {sum=0} # initialization for clarity and safety
function pp() {
  u="+Ki+Mi+Gi+Ti+Pi+Ei";
  split(u,unit,"+");
  v=sum;
  for(i=1;i<7;i++) {
    if(v<1024) break;
    v/=1024;
  }
  printf("%.3f %sB\n", v, unit[i]);
}
{sum+=$5}
END{pp()}'

例如:

$ ds ~        
72.891 GiB

现在,我发现了所有建议的ls调用中都缺少的另一个选项:-q。如果没有此选项,则脚本将在某些文件名包含换行符的情况下中断。编写真正可靠的shell脚本太难了……
Sergey Vlasov 2013年

@SergeyVlasov我发布的脚本不应与此类文件分开,而只是忽略多余的行。如果精心制作的文件的多余一行带有第五个冒号(包含数值),则会出现唯一的问题。您的建议确实可以避免这种情况。感谢您的提示,脚本已更新。
jlliagre 2013年

优秀的答案。+1先生
爱媛,2014年

这是最可靠的解决方案之一。它可以处理带有空格或引号的文件名,并打印出易于理解的大小。
basic6

@KIAaze感谢您检查和修复我的代码!
jlliagre

8

某些版本的du支持参数--apparent-size显示明显的大小而不是磁盘使用情况。因此,您的命令将是:

du -hs --apparent-size

从Ubuntu 12.04 LTS随附的du手册页中:

--apparent-size
      print apparent sizes,  rather  than  disk  usage;  although  the
      apparent  size is usually smaller, it may be larger due to holes
      in (`sparse') files, internal  fragmentation,  indirect  blocks,
      and the like

1
不起作用:报告一些空的空间
Karl Forner 2014年

1
这对我有用。
connorbode 2014年

2
当您比较不同文件系统上的目录时,它提供的大小明显不同。例如,同一文件夹在zfs文件系统上的表观大小为290Gb,在exFat上的表观大小为324Gb。上述解决方案的大小相同。
Pixus.ru 2016年

4

只是一种替代方法,使用ls

ls -nR | grep -v '^d' | awk '{total += $5} END {print total, "Total"}'

ls -nR-n-l,但是列出数字UID和GID并 -R递归列出子目录。

grep -v:反转匹配感,以选择不匹配的行。(-v由POSIX指定。)。'^ d'将排除目录。

LS命令:http : //linux.about.com/od/commands/l/blcmdl1_ls.htm

Man Grep:http//linux.die.net/man/1/grep

编辑

编辑为建议@谢尔盖·弗拉索夫(Sergey Vlasov)。


使用-n选项ls代替-l(显示UID / GID号代替名称)更安全,因为用户名和组名可以包含空格(例如,如果winbindsssd用于将系统连接到Windows域,则可以得到类似的组名domain users) 。由于不需要查找用户名和组名,因此它也应该更快。
谢尔盖·弗拉索夫

谢谢,这比find -exec ls快得多!
gpothier

4

假设您使用的du是GNU coreutils,此命令应计算目录内任意数量的常规文件的总表观大小,而对文件数没有任何限制:

find . -type f -print0 | du -scb --files0-from=- | tail -n 1

如果内部有一些硬链接的文件,并且您想分别计算每个硬链接(默认情况下只计算一次多个硬链接),请添加此-l选项。dudu

与plain的最重要区别du -sb是递归du还计算目录的大小,不同文件系统对目录的报告方式不同。为避免这种情况,该find命令仅用于将常规文件传递给du。另一个区别是符号链接将被忽略(如果应该对符号链接进行计数,find则应调整命令)。

此命令也将比plain消耗更多的内存du -sb,因为使用--files0-from=FILEmake的du存储设备和所有已处理文件的inode编号,而不是仅记住具有多个硬链接的文件的默认行为。(如果该-l选项用于多次计数硬链接,则这不是问题,因为存储设备和inode编号的唯一原因是跳过已处理的硬链接文件。)

如果您想获得总大小的可读格式,只需添加-h选项(之所以有效,du是因为仅被调用一次并计算总大小本身,这与其他一些建议的答案不同):

find . -type f -print0 | du -scbh --files0-from=- | tail -n 1

或(如果您担心的某些影响-b会被覆盖-h

find . -type f -print0 | du -sc --apparent-size -h --files0-from=- | tail -n 1

不知道要为FreeBSD做些什么-尽管-b可能被代替-A -B 1,但没有等效的--files0-from=-xargs如果文件列表大于ARG_MAX(以及一些供人类阅读的外部解决方案),则使用将需要一些解决方法。
谢尔盖·弗拉索夫

3

如果只需要文件的大小(不包括目录占用的空间),则可以执行以下操作

find . -type f -print0 | xargs -0 du -scb | tail -n 1

@SergeyVlasov指出,如果文件多于,则此操作将失败argmax。为了避免这种情况,您可以使用以下方法:

find . -type f -exec du -sb '{}' \; | gawk '{k+=$1}END{print k}'

1
如果目录中包含的文件太多而无法满足execve()参数大小的限制,则此命令将以静默方式给出错误的结果-在这种情况下,xargs它将du多次调用,并且每次调用将仅为其打印总计完整文件列表中的,然后tail将仅显示最后一部分的总大小。
Sergey Vlasov

1
@SergeyVlasov好点,我没有想到这一点,谢谢,答案已更新。
terdon
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.