CLI AI

统计目录里的文件:递归并按类型分组

2026-07-25

find . -type f | wc -l 会统计当前目录下的所有文件(含子目录),并且不把目录本身算进去。真正有意思的通常是拆分结果——按扩展名、按子目录——而且有一种情况下 wc -l 会骗你:文件名里带换行。

1. 一共有多少文件

clai
$ clai 这个文件夹和所有子文件夹里一共有多少文件→ find . -type f | wc -l20

-type f 排除了目录和符号链接,所以这个数字是有意义的。同一个目录下 ls | wc -l 会回答 3:它只看顶层,并且把目录也算作条目。

2. 按扩展名拆分

clai
$ clai 按扩展名统计文件数量→ find . -type f -name '*.*' | sed 's/.*\.//' | sort | uniq -c | sort -rn      7 jpg      6 py      4 md      1 txt      1 png      1 bin

这通常才是问题背后的问题:这个目录到底由什么组成。-name '*.*' 会排除没有扩展名的文件;不加它,sed 会把整个文件名还给你。

3. 按子目录拆分

clai
$ clai 统计每个子目录里的文件数→ for d in */; do printf '%5s %s\n' "$(find "$d" -type f | wc -l)" "$d"; done    3 docs/    8 img/    7 src/

对顶层目录做循环,在每个目录里递归计数。隐藏目录匹配不上 */,所以这里的总和小于全部数量。

4. 不算隐藏文件

clai
$ clai 统计文件但跳过隐藏文件→ find . -type f -not -path '*/.*' | wc -l18

20 对 18,差的正好是那两个点开头的文件。-not -path '*/.*' 同时也排除了 .git 这类隐藏目录里的一切,而那通常正是你的本意。

5. 陷阱:文件名里的换行

clai
$ clai 即使文件名里有换行也要可靠地统计文件数→ find . -type f -printf '.' | wc -c21

用一个名字横跨两行的文件验证过:同一目录下 find . -type f | wc -l 报的是 22。wc -l 数的是行,不是文件。-printf '.' 每个文件输出一个点,数字就又对了。不依赖 GNU 扩展的可移植写法是 find . -type f -print0 | tr -dc '\0' | wc -c。

6. 一行里同时给出文件数和目录数

clai
$ clai 显示这里有多少文件、多少目录→ printf 'files: %s\ndirs: %s\n' "$(find . -type f | wc -l)" "$(find . -type d | wc -l)"

-type d 把当前目录也算了进去,所以目录数总比你以为的多一个。

Gotchas

  • ls | wc -l 数的不是那回事。 它不进子目录,却把目录算进来,还跳过点开头的文件。回答你这个问题的是 find -type f。
  • wc -l 会栽在名字里的换行上。 已验证:21 个文件,答案 22。如果目录来自外部——用户上传、解压出来、爬虫抓的——就用 -printf '.' 或 -print0 来数。
  • find . 会走进隐藏目录。 在仓库里,光是 .git 就能给总数添上几千个文件。用 -not -path '*/.*' 过滤,否则这个数字毫无意义。

Related questions

怎么只统计顶层? find . -maxdepth 1 -type f | wc -l 不会下到子目录。

怎么只统计某一类文件? find . -type f -name '*.log' | wc -l。大小写有区别,不想区分就用 -iname。

要的是体积而不是数量呢? du -sh . 给出总大小,du -h --max-depth=1 | sort -h 按子目录拆分。

See also

CliAI 会把"按类型统计有多少文件"变成完整的管道,并在执行前先显示出来。一行安装。