获取递归文件计数(如“du”,但文件数量而不是大小)

获取递归文件计数(如“du”,但文件数量而不是大小)

由于 rsnapshot 的性能问题,我想递归地识别包含大量文件的目录。我认为问题不在于文件的大小,而在于特定子目录中的文件数量,因为代数(daily.0、daily.1、...)不是易变的,与文件总数相比变化很小。

如果Unix 命令du仅返回文件计数而不返回文件大小总和,那么它正是我想要的。

我已经有一个输出文件计数的 bash 脚本全部的直接的子目录(递归到子目录),但是使用起来很麻烦,因为我必须越挖越深,总是要等待。

还发现了一个剧本深入挖掘,但不总结子目录的文件数。它仅显示此目录中的文件数量,而不显示其子目录中的文件数量。

不一定是 shell 脚本 - 我对其他脚本语言持开放态度,如 Ruby、Python、Perl、JavaScript 等

例子:

dir1/
   file1
   subdir1/
       file2, file3, file4, file5
   subdir2/
       file6, file7, file8
       subdir3/
           file9
dir2/
    fileA, fileB

所需输出(列出子目录并汇总到顶部):

4   dir1/subdir1
1   dir1/subdir2/subdir3
4   dir1/subdir2
9   dir1/
2   dir2/

我什么想要(仅列出总数):

9   dir1/
2   dir2/

不是(仅列出.目录的文件数):

4   dir1/subdir1
1   dir1/subdir2/subdir3
3   dir1/subdir2
1   dir1/
2   dir2/

答案1

尝试这样的事情:

find . -type f | perl -aF/ -lne 'for (my $i=0; $i < @F-1; ++$i) { print join("/",@F[0...$i]); }' | sort | uniq -c

find . -type f打印文件:

./dir1/subdir2/file8
./dir1/subdir2/file7
./dir1/subdir2/subdir3/file9
./dir1/subdir2/file6
./dir1/file1
...

perl -aF/ -lne 'for (my $i=0; $i < @F-1; ++$i) { print join("/",@F[0...$i]); }'将每个文件名转换./a/b/c为一组目录.,,./a./a/b

笔记:

不适用于文件名中的换行符。您可以在 hash 中使用-print0in find-0inperl和 put 计数器为每个目录。

编辑:

灵感来自@Gilles's回答:

find . -depth -print0 |
perl -0 -ne '
my $depth = tr!/!/!;
for (my $i = $prev_depth; $i <= $depth; ++$i) { $totals[$i] = 0; }
if ( -f $_ ) {
  for (my $i = 0; $i <= $depth; ++$i) { ++$totals[$i]; }
} else {
  print "$totals[$depth]\t$_\n";
}
$prev_depth = $depth;
'

适用于文件名中的换行符。适用于空目录。不需要额外的sort | uniq -c.

答案2

如果您有find(可用于迭代目录中的所有文件,包括目录子目录中的所有文件)和wc(计算文件中的行数),那么单行怎么样?

find <directory> | wc

其中<directory>是您要计算所有文件的目录。这将打印出三个数字;第一个是 find 返回的行数。我想默认情况下会查找文件和目录,因此这将给出文件和目录(包括其本身)find的总数。<directory><directory>

find是一个极其灵活的命令。如果您真的只对文件感兴趣并且不想计算目录,那么

find <directory> -type f | wc

会成功的。例如,要计算当前目录中包含的所有文件(无论深度如何),您可以执行以下操作

find . -type f | wc

注意事项:默认情况下find不会遵循符号链接等;如果您的文件位于各种不同的文件系统或您拥有的文件系统上,那么您应该查看手册页,因为find它可以设置为处理几乎任何事情。另请注意,这wc是对行进行计数,因此,如果您碰巧有名称中包含换行符的文件(技术上可行,但据我所知总体上不是一个好主意)或类似的东西,那么您会得到有趣的答案。

答案3

根据我的评论,对此的变体可能会满足您的需求:

find . -depth -type d -exec /bin/sh -c 'printf "%5d %s\n" "$(find {} -type f -printf . | wc -c)" "{}"' \;

(正确执行的旅肯定会正确地射击我,因为我多次计算更深层次子目录的结果,并希望文件系统缓存在某个时刻拥有树的整个元数据,并且每次都会生成一个新的外壳,但这是一个开始。)

根据您的示例结构,我得到:

    4 ./dir1/subdir1
    1 ./dir1/subdir2/subdir3
    4 ./dir1/subdir2
    9 ./dir1
    2 ./dir2
   11 .

(要排除当前工作目录,请将外部更改find .find *或使用find . -mindepth 1

相关内容