查找目录中的文件数

Posted

技术标签:

【中文标题】查找目录中的文件数【英文标题】:Find the number of files in a directory 【发布时间】:2011-04-11 18:05:38 【问题描述】:

Linux 中是否有任何方法可以在 O(1) 中(与文件数无关)计算目录中的文件数(即直接子级),而不必先列出目录?如果不是 O(1),有没有合理有效的方法?

我正在寻找ls | wc -l 的替代品。

【问题讨论】:

ls| wc -l 的哪一部分不是 O(1)? ls | wc -l 将导致 ls 对所有文件执行 opendir()、readdir() 和可能的 stat()。这通常至少是 O(n)。 @halfdan: ls 输出所有文件,所以是 O(n) 是的,我的错。我在想 O(1) 和 O(n) 是一样的,虽然我应该更清楚。 你不能只使用 shell globbing 吗? 【参考方案1】:

对于当前目录中所有文件的数量,试试这个:

ls -lR * | wc -l

【讨论】:

【参考方案2】:

我认为您可以使用 find 对此进行更多控制:

find <path> -maxdepth 1 -type f -printf "." | wc -c
find -maxdepth 1 不会深入到文件的层次结构中。 -type f 允许仅过滤文件。同样,您可以将-type d 用于目录。 -printf "." 为每场比赛打印一个点。 wc -c 计算字符数,因此它计算由 print 创建的点...这意味着计算给定路径中存在的文件数。

【讨论】:

【参考方案3】:

ls-U 选项不在 POSIX 中,而在 OS X 的 ls 中,它与 GNU ls 的含义不同,即它使 -t-l 使用创建时间而不是修改时间。 -f 在 POSIX 中作为 XSI 扩展。 GNU 的手册ls-f 描述为do not sort, enable -aU, disable -ls --color-U 描述为do not sort; list entries in directory order

POSIX 是这样描述-f 的:

强制将每个参数解释为目录并列出在每个插槽中找到的名称。此选项应关闭-l-t-s-r,并应打开-a; order 是条目在目录中出现的顺序。

当文件名包含换行符时,ls|wc -l 之类的命令会给出错误的结果。

在 zsh 中你可以这样做:

a=(*(DN));echo $#a

D (glob_dots) 包括名称以句点开头的文件,N (null_glob) 导致命令不会在空目录中导致错误。

在 bash 中也一样:

shopt -s dotglob nullglob;a=(*);echo $#a[@]

如果 IFS 包含 ASCII 数字,请在 $#a[@] 周围添加双引号。添加shopt -u failglob 以确保未设置failglob

一个可移植的选项是使用find

find . ! -name . -prune|grep -c /

如果文件名不包含换行符,grep -c / 可以替换为 wc -l! -name . -prune-mindepth 1 -maxdepth 1 的便携式替代品。

或者这是另一种选择,通常不包含名称以句点开头的文件:

set -- *;[ -e "$1" ]&&echo "$#"

但是,上面的命令确实包含名称以句点开头的文件,当设置了诸如 bash 中的 dotglob 或 zsh 中的 glob_dots 之类的选项时。当* 不匹配任何文件时,该命令会导致使用默认设置的 zsh 出错。

【讨论】:

【参考方案4】:

我使用这个命令..就像一个魅力..只改变最大深度..即子目录

find * -maxdepth 0 -type d -exec sh -c "echo -n  ' ' ; ls -lR  | wc -l" \;

【讨论】:

【参考方案5】:

使用 ls -1 | wc -l

【讨论】:

ls -l 会给你一个额外的总块数行,这将是计数时的额外行。 ls -1 没有。 @VenkatarameshKommoju,a) 你没有解释为什么这应该比ls | wc -l 更好,b) 它不是。【参考方案6】:

可以通过统计(stat(1) 或 stat(2))给定目录并观察到该目录的链接数量来获取给定目录的子目录数量,而无需遍历整个列表。具有 N 个子目录的给定目录的链接计数为 N+2,每个子目录的“..”条目有一个链接,“.”条目有两个链接。和给定目录的“..”条目。

但是,如果不遍历整个列表,就无法获得所有文件(无论是常规文件还是子目录)的数量——这是正确的。

“/bin/ls -1U”命令不会获取所有条目。它将获取那些不以点 (.) 字符开头的目录条目。例如,它不会计算在许多登录 $HOME 目录中找到的“.profile”文件。

可以使用“/bin/ls -f”命令或“/bin/ls -Ua”命令来避免排序并获取所有条目。

也许不幸的是,“/bin/ls -f”命令或“/bin/ls -Ua”命令也将计算“。”和每个目录中的“..”条目。您必须从计数中减去 2 以避免计算这两个条目,如下所示:

expr `/bin/ls -f | wc -l` - 2     # Those are back ticks, not single quotes.

在管道“ls”输出时,“/bin/ls -Ua”命令不需要 --format=single-column (-1) 选项,如本例中的“wc”。如果输出不是终端,“ls”命令将自动将其输出写入单个列。

【讨论】:

同意ls -fls -1U 更好(我认为-f 是用于这种管道的),但我希望ls 可以选择用NUL 字符来终止每个文件名换行符。 在 Linux 上:-b, --escape print C-style escapes for nongraphic characters;这会将嵌入的换行符打印为\n【参考方案7】:

readdir 并不像您想象的那么昂贵。诀窍是避免统计每个文件,并(可选)对 ls 的输出进行排序。

/bin/ls -1U | wc -l

避免在你的 shell 中使用别名,不对输出进行排序,并且每行列出 1 个文件(在将输出通过管道传输到 wc 时不是绝对必要的)。

原始问题可以改写为“目录的数据结构是否存储条目数的计数?”,答案是否定的。没有比 readdir(2)/getdents(2) 更有效的文件计数方法了。

【讨论】:

为了避免别名,你也可以说\ls。检查\curl … | bash … what's the slash for?【参考方案8】:

据我所知,没有更好的选择。此信息可能与此问题无关,您可能已经知道在 Linux 下(通常在 Unix 下)目录只是包含其他文件列表的特殊文件(我知道确切的细节将取决于特定文件系统,但这是一般的想法)。并且无需遍历整个列表就无需调用来查找条目总数。如果我错了,请纠正我。

【讨论】:

以上是关于查找目录中的文件数的主要内容,如果未能解决你的问题,请参考以下文章

如何使用 Python 计算目录中的文件数

C++ 查找指定目录下的文件数

C++ 查找指定目录下的文件数

使用聚合查找最新批次中的文件数

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

sh 计算目录中的文件数(递归)