问题描述
我可以列出所有目录
find ./ -type d
我试图使用以下命令列出每个目录的内容并计算每个目录中的文件数
find ./ -type d | xargs ls -l | wc -l
但这是求和的总和
find ./ -type d | xargs ls -l
有没有一种方法可以计算每个目录中的文件数?
最佳解决方案
假设您已找到GNU,请让其查找目录,然后让bash进行其余操作:
find . -type d -print0 | while read -d '' -r dir; do
files=("$dir"/*)
printf "%5d files in directory %s\n" "${#files[@]}" "$dir"
done
次佳解决方案
这将打印当前目录级别的每个目录的文件计数:
du -a | cut -d/ -f2 | sort | uniq -c | sort -nr
第三种解决方案
您可以安排查找所有文件,删除文件名,在一行中仅包含每个文件的目录名,然后计算每个目录出现的次数:
find . -type f |
sed 's%/[^/]*$%%' |
sort |
uniq -c
唯一的麻烦是,如果您有任何包含换行符的文件名或目录名,这是不太可能的。如果您真的要担心文件名或目录名中的换行符,建议您找到它们并进行修复,以使它们不包含换行符(并悄悄说服有罪的一方注意其方式的错误)。
如果您对当前目录的每个sub-directory中的文件计数感兴趣,对任何sub-directories中的任何文件以及直接sub-directory中的文件计数,那么我将sed
命令改编为仅打印top-level:
find . -type f |
sed -e 's%^\(\./[^/]*/\).*$%\1%' -e 's%^\.\/[^/]*$%./%' |
sort |
uniq -c
第一个模式捕获名称的开头,点,斜杠,直到下一个斜杠和斜杠的名称,然后仅用第一部分替换该行,因此:
./dir1/dir2/file1
被替换为
./dir1/
第二个替换直接在当前目录中捕获文件;它们的末尾没有斜杠,而是由./
代替。然后,排序和计数仅对名称数起作用。
第四种方案
这是一种方法,但可能不是最有效的。
find -type d -print0 | xargs -0 -n1 bash -c 'echo -n "$1:"; ls -1 "$1" | wc -l' --
提供这样的输出,并带有目录名称,后跟该目录中的条目数。请注意,输出计数还将包括目录条目,这些目录条目可能不是您想要的。
./c/fa/l:0
./a:4
./a/c:0
./a/a:1
./a/a/b:0
第五种方案
每个人的解决方案都有一个缺点或另一个缺点。
find -type d -readable -exec sh -c 'printf "%s " "$1"; ls -1UA "$1" | wc -l' sh {} ';'
说明:
-
-type d
:我们对目录感兴趣。 -
-readable
:如果可能列出其中的文件,我们只需要它们。请注意,当find
尝试在目录中搜索更多目录时,它仍然会发出错误消息,但这会阻止为它们调用-exec
。 -
-exec sh -c BLAH sh {} ';'
:对于每个目录,请运行此脚本片段,并将$0
设置为sh
,并将$1
设置为文件名。 -
printf "%s " "$1"
:可移植且最小程度地打印目录名称,后跟一个空格,而不是换行符。 -
ls -1UA
:按目录顺序列出文件(每行一个)(以避免使管道停顿),仅排除特殊目录.
和..
-
wc -l
:计算行数
第六种方案
find . -type f | cut -d/ -f2 | sort | uniq -c
-
find. -type f
查找类型文件的所有项目 -
cut -d/ -f2
剪切其特定的文件夹 -
sort
对文件夹名称列表进行排序 -
uniq -c
返回已计算每个文件夹名称的次数
第七种方案
也可以通过遍历ls而不是find来完成
for f in */; do echo "$f -> $(ls $f | wc -l)"; done
说明:
for f in */;
-遍历所有目录
do echo "$f ->
-打印每个目录名称
$(ls $f | wc -l)
-为此目录调用ls并计数行
第八种方案
使用find
代替du
的Sebastian’s答案的稍作修改的版本(以排除du
必须执行且从未使用的file-size-related开销):
find ./ -mindepth 2 -type f | cut -d/ -f2 | sort | uniq -c | sort -nr
-mindepth 2
参数用于排除当前目录中的文件。如果将其删除,则会看到许多类似以下内容的行:
234 dir1
123 dir2
1 file1
1 file2
1 file3
...
1 fileN
(就像基于du
的变体一样)
如果确实也需要计算当前目录中的文件,请使用以下增强版本:
{ find ./ -mindepth 2 -type f | cut -d/ -f2 | sort && find ./ -maxdepth 1 -type f | cut -d/ -f1; } | uniq -c | sort -nr
输出将如下所示:
234 dir1
123 dir2
42 .
第九种方案
这应该返回目录名称,后跟目录中的文件数。
findfiles() {
echo "$1" $(find "$1" -maxdepth 1 -type f | wc -l)
}
export -f findfiles
find ./ -type d -exec bash -c 'findfiles "$0"' {} \;
输出示例:
./ 6
./foo 1
./foo/bar 2
./foo/bar/bazzz 0
./foo/bar/baz 4
./src 4
之所以需要export -f
,是因为find
的-exec
参数不允许执行bash函数,除非您显式调用bash,并且需要将在当前作用域中定义的函数显式导出到新的shell中。