查找目录中的文件数
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 -f
比ls -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 下)目录只是包含其他文件列表的特殊文件(我知道确切的细节将取决于特定文件系统,但这是一般的想法)。并且无需遍历整个列表就无需调用来查找条目总数。如果我错了,请纠正我。
【讨论】:
以上是关于查找目录中的文件数的主要内容,如果未能解决你的问题,请参考以下文章