![计算“documents/”中有多少个子目录和文件](https://linux22.com/image/162534/%E8%AE%A1%E7%AE%97%E2%80%9Cdocuments%2F%E2%80%9D%E4%B8%AD%E6%9C%89%E5%A4%9A%E5%B0%91%E4%B8%AA%E5%AD%90%E7%9B%AE%E5%BD%95%E5%92%8C%E6%96%87%E4%BB%B6.png)
我正在通过 gameshell 学习 Linux。
正如标题所说;我需要查找“documents/”中的子目录和文件的数量。该命令运行良好,但它不是正确的答案。这是我的命令:
find documents/ -type f | wc -l | awk '{print $1}'
我究竟做错了什么 ?
答案1
包含-type f
意味着它只包含文件,而不包含目录。尝试删除此部分,看看是否效果更好。
您可能想尝试删除| awk '{ print $1 }'
该部分以查看该部分是否确实必要。
答案2
您的命令仅计算从 输出的行数find
。该find
命令只会输出目录中或documents
目录下常规文件的路径名。
如果您想要计算目录中或目录下的常规文件和目录的数量,documents
您可以在zsh
shell 中执行以下操作:
set -- documents/**/*(DN/) documents/**/*(DN.)
printf 'There are %d regular files and directories in or under "documents"\n' "$#"
这设置了位置参数( $1
、等) 为扩展两个文件名通配模式和 $2
的结果,第一个将匹配所有常规文件,而第二个匹配目录(无论它们是否隐藏)。该模式“递归”地匹配子目录。documents/**/*(DN/)
documents/**/*(DN.)
**
一旦设置了位置参数,特殊变量$#
将保存这些参数的数量。
在里面bash
shell中,不支持全局限定符 (DN/)
并且(DN.)
,您可以使用循环:
shopt -s globstar dotglob nullglob
count=0
for pathname in documents/**/*; do
if [[ -f $pathname ]] || [[ -d $pathname ]]; then
[[ ! -h $pathname ]] && count=$(( count + 1 ))
fi
done
printf 'There are %d regular files and directories in or under "documents"\n' "$count"
这比zsh
变体稍微复杂一些,但应该很容易理解。我们首先设置一些 shell 选项,以便我们可以使用**
,以便我们计算隐藏名称,并且如果没有匹配项,模式将解析为空(最后两个相当于glob 限定符中的theD
和 the )。N
zsh
在循环内,我们测试当前路径名是常规文件还是目录,而不是符号链接。如果它是常规文件或目录,我们就会对其进行计数。
在 中sh
,您必须求助于find
:
find documents \( -type f -o -type d \) -exec echo . \; | wc -l
我们在 中或下查找常规文件或目录documents
,对于每个这样的东西,我们在一行上单独输出一个点。然后wc -l
计算生成的行数。这可以避免多次计算带有嵌入换行符的文件名。
请注意,此变体也会对documents
目录本身进行计数。
答案3
处理可能包含空格、换行符或文件名的最安全方法任何事物是将每个文件名转换为单个安全字符(如X
)。
使用 find 我们可以对找到的每个文件/目录执行命令:
find documents/ -type f -exec printf X \; ; echo
这将生成一个包含与X
文件数量一样多的字符串(更改f
为d
以计算目录数)。要将其转换为数字,我们可以捕获命令的结果并打印结果字符串的大小:
$ str="$(find documents -type d -exec printf X \;)"
$ echo "${#str}"
23
或者直接计算字节数(等于字符,因为唯一使用的字符是X
):
$ find testit -type d -exec printf X \; | wc -c
find 命令对点文件进行计数,并且可以跟随符号链接(使用 -L)或不跟随符号链接(默认情况下)。如果默认情况下避免点文件和遵循符号链接(到文件,而不是从 bash 4.3 开始到目录)不是问题,我们可以使用通配
$ ( shopt -s globstar; set -- documents/**/*/; echo "$#" )
23
对于目录,以及:
$ ( shopt -s globstar; set -- documents/**/*; echo "$#" )
65
对于所有文件和目录(不遵循目录符号链接)。