用 find 配合 while 循环统计每个子目录文件数最可靠:先 find 列出子目录,再对每个目录单独执行 find -maxdepth 1 -type f | wc -l,注意加引号处理空格、重定向错误输出。

想看每个子目录里各有多少个文件?用 find + while
直接统计整个目录树的总数容易,但要拆解到「每个子目录分别多少文件」,find 配合 while 是最稳的组合。关键不是只跑一次 find,而是先列出所有子目录,再对每个目录单独计数。
常见错误是写成 find . -type d -exec find {} -maxdepth 1 -type f \; | wc -l —— 这会把所有文件混在一起计数,根本分不清归属。
- 正确做法:先用
find . -maxdepth 1 -type d ! -path "."列出一级子目录(排除当前目录.) - 再用
while read dir循环执行find "$dir" -maxdepth 1 -type f 2>/dev/null | wc -l - 路径含空格?必须用
"$dir"加双引号,否则遇到My Documents类目录直接中断 - 权限不足的子目录会被
find报错,加2>/dev/null屏蔽 stderr,避免干扰输出格式
按文件类型或后缀分组统计数量?用 find -name 搭配括号逻辑
比如想知道 .log、.conf、.sh 各有多少个,不能靠多次跑 find -name "*.log"——效率低,还容易漏掉同名但大小写不同的情况(如 .LOG)。
find 的 -name 不支持正则,但支持 -o(or)和括号分组,注意括号要转义或用单引号包裹,否则 shell 会提前解析。
- 统计三种后缀:
find . -type f \( -name "*.log" -o -name "*.conf" -o -name "*.sh" \) | wc -l - 想分开看每种数量?得用循环:
for ext in log conf sh; do echo "$ext: $(find . -type f -name "*.$ext" | wc -l)"; done - 区分大小写?默认区分;想忽略,用
-iname替代-name - 注意:
-name "*.log"不匹配隐藏文件.gitignore,但匹配app.log和error.log.bak
为什么 tree -a | tail -1 不适合做分布分析?
tree 最末行显示类似 12 directories, 87 files,看着方便,但它只给总数,不提供层级分布。更关键的是:tree 默认不进入权限拒绝的子目录,也不会报错提示你“这里漏了”,静默跳过导致结果偏低。
还有两个硬伤:
-
tree -L 2可控深度,但无法指定「只统计某一层级下的文件数」,它总是从根开始展开 - 输出含 ANSI 颜色码时(比如 alias 里开了
tree --color),tail -1可能截到控制字符,导致解析失败 - 没有
-type f级别的过滤能力,tree -a把符号链接、设备节点全算进 “files”,而实际业务中往往只关心常规文件
超大目录下实时观察分布?别等 wc -l 结束,改用 printf 计数
当目标目录有几十万文件时,find ... | wc -l 要等最后才出结果,中间完全没反馈。这时候用 -printf 打点,配合 wc -c,既能提速又能看到进度。
- 单目录计数:
find /big/dir -maxdepth 1 -type f -printf '.' 2>/dev/null | wc -c—— 每个文件打一个.,wc -c数字节,比wc -l更可靠(空行不影响) - 要分目录看?用
-printf '%h\0'输出每个文件所在目录路径(\0分隔),再用awk或sort | uniq -c统计频次 - 注意:
-printf是 GNU find 特性,macOS 自带的find不支持,得装gnu-findutils - 如果目录结构极深、文件名含换行符,只有
find ... -print0+xargs -0或while IFS= read -r -d ''才真正安全
find /var/log 能扫完所有子目录,但遇到 /var/log/journal 这类 systemd-journald 管理的二进制日志目录,普通用户根本进不去,find 默默跳过,你却以为数据完整。要么加 sudo,要么提前用 ls -ld /var/log/journal 确认可访问性。


















