目录中文件名可能包含换行符(或任何其他奇怪字符)的文件数

目录中文件名可能包含换行符(或任何其他奇怪字符)的文件数

我想知道特定目录内的项目(文件、子目录等)数量。

似乎有很多关于它的问题,但大多数(如果不是全部)答案似乎都依赖于wc -l。例如:

ls -1 | wc -l

但如果一个或多个文件的名称中包含新行,则会给出错误的答案。这里的另一个问题是ls -1可能返回的不仅仅是文件。

一个不可移植的答案是隐藏在数千个类似问题之一的评论中。有效,但不幸的是它依赖-printf于我的发行版中不可用的。

find -maxdepth 1 -type f -printf "\n" | wc -l (由神极客)

是否有更便携的解决方案可以正确处理名称中包含任何字符的文件?

答案1

假设您不需要位置参数,您可以设置它们并计算它们:

set -- .* *
echo $#

这可以在函数中或子 shell 中,以限制以下的影响set

countfiles() {
    set -- .* *
    echo $#
}

countfiles

或者

(set -- .* *; echo $#)

这里只有函数或子 shell 的参数被“丢失”,主上下文中的位置参数保持不变。

您也可以指定路径:

set -- path/to/dir/.* path/to/dir/*
echo $#

隐藏文件的具体扩展取决于 shell 设置;POSIX shell在扩展时应包含....*,所以这些都会被计算在内。如果您不想计算它们,请检查它们是否包括(查看$1$2),并从结果中减去 2。

在某些 shell 中,可以配置点扩展,和/或.[^.]* ..?*可以使用其他扩展 ( ) 来排除...;因此在 Bash 中,使用dotglob

shopt -s dotglob
set -- *
echo $#

答案2

下面的代码可能不是很优雅,但应该是可移植的。它依赖于 shell 算术:

n=0; for f in *; do n=$((n+1)); done; echo "$n"

请注意,这不会计算隐藏文件。如果您也需要它们,则必须扩展迭代列表:

n=0; for f in * .*; do n=$((n+1)); done; echo "$n"

根据您的外壳,n=$((n+1))可以将其打入((n++))

笔记显式的 shell 循环使得这种方法相当慢,如果您正在处理包含数千个文件的目录,这可能会变得很明显。这斯蒂芬·基特的回答速度要快得多,但如果您不熟悉 shell 脚本,可能会有点晦涩难懂。

答案3

如果你想POSIX 合规性(这也意味着排除bash及其shopt -s dotglob),计算目录中文件的一种方法是这种有点慢的方法

find . -path './?*' ! -type f -prune -o -type f -exec echo x \; | wc -l

如果你不关心你拥有什么,你可以大大简化它

find . -path './?*' -prune -exec echo x \; | wc -l

事实上,建立在另一个答案,这将为您提供当前目录中所有非目录(可能只是文件,但如果存在的话,将包括设备和管道)的计数

( set -- * .* ; all=$#; set -- */ .*/ ; echo $(( all - $# -2 )) )

答案4

尝试查找索引节点号...这不涉及文件名。

$ find . -type f -printf '%i\n' 

但是看到你的发现没有 printf

$ find . -type f -name 'test*' -exec stat -c "%i" {} \; 

将仅返回 inode

$ find . -type f -name 'test*' -exec stat -c "%i" {} \; | wc -l

会给你你需要的计数。

希望这可以帮助。

相关内容