由于 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 中使用-print0
in find
、-0
inperl
和 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