26

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

我正在寻找ls | wc -l.

4

8 回答 8

39

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

/bin/ls -1U | wc -l

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

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

于 2010-09-13T16:49:37.657 回答
11

通过统计(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”命令将自动将其输出写入单个列。

于 2010-09-13T18:55:08.710 回答
3

for的-U选项ls不在 POSIX 中,在 OS X 中ls它与 GNU 具有不同的含义ls,即它生成-t-l使用创建时间而不是修改时间。-f在 POSIX 中作为 XSI 扩展。GNU 手册ls-fasdo not sort, enable -aU, disable -ls --color-Uas描述为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 "$#"

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

于 2016-05-12T00:27:37.030 回答
2

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

find * -maxdepth 0 -type d -exec sh -c "echo -n {} ' ' ; ls -lR {} | wc -l" \;
于 2013-12-11T18:13:55.537 回答
2

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

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

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

于 2010-09-13T16:03:36.847 回答
1

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

ls -lR * | wc -l
于 2018-08-02T07:15:09.177 回答
-1

使用 ls -1 | wc -l

于 2010-09-14T11:30:20.837 回答