当前位置: 首页>>技术教程>>正文


如何计算每个目录中的文件数?

, ,

问题描述

我可以列出所有目录

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代替duSebastian’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中。

参考资料

本文由Ubuntu问答整理, 博文地址: https://ubuntuqa.com/article/7288.html,未经允许,请勿转载。