获取列表,将大小相加,然后按所有者排序(使用 Perl)
perl -wE'
chdir (shift // ".");
for (glob ".* *") {
next if not -f;
($owner_id, $size) = (stat)[4,7]
or do { warn "Trouble stat for: $_"; next };
$rept{$owner_id} += $size
}
say (getpwuid($_)//$_, " => $rept{$_} bytes") for sort keys %rept
'
我没有对其进行基准测试,值得尝试使用迭代目录的方法,而不是 glob-ed(虽然我发现 glob 在related problem)。
与ls 相比,我希望运行时更好,因为单个目录中的文件列表变长了,这显着减慢了速度。这是由于系统造成的,所以 Perl 也会受到影响,但据我回忆,它处理得更好。但是,只有当条目达到 50 万左右而不是几千时,我才看到速度急剧下降,所以我不确定为什么它在您的系统上运行缓慢。
如果这需要在它找到的目录中递归,则使用File::Find。例如
perl -MFile::Find -wE'
$dir = shift // ".";
find( sub {
return if not -f;
($owner_id, $size) = (stat)[4,7]
or do { warn "Trouble stat for: $_"; return };
$rept{$owner_id} += $size
}, $dir );
say (getpwuid($_)//$_, "$_ => $rept{$_} bytes") for keys %rept
'
这会在 2 秒多一点的时间内扫描一个 2.4 Gb 的目录,其中大部分是子目录层次结构上的小文件。 du -sh 花了大约 5 秒(第一轮)。
将这两者合二为一是合理的
use warnings;
use strict;
use feature 'say';
use File::Find;
use Getopt::Long;
my %rept;
sub get_sizes {
return if not -f;
my ($owner_id, $size) = (stat)[4,7]
or do { warn "Trouble stat for: $_"; return };
$rept{$owner_id} += $size
}
my ($dir, $recurse) = ('.', '');
GetOptions('recursive|r!' => \$recurse, 'directory|d=s' => \$dir)
or die "Usage: $0 [--recursive] [--directory dirname]\n";
($recurse)
? find( { wanted => \&get_sizes }, $dir )
: find( { wanted => \&get_sizes,
preprocess => sub { return grep { -f } @_ } }, $dir );
say (getpwuid($_)//$_, " => $rept{$_} bytes") for keys %rept;
当非递归运行时(默认情况下),我发现它的执行与上面的 one-dir-only 代码大致相同。
请注意,File::Find::Rule 接口有很多便利,但在一些重要的用例中是slower,这里显然很重要。 (该分析应该重做,因为它已经有几年历史了。)