CLI AI

Count files in a directory, recursively and by type

2026-07-25

find . -type f | wc -l counts every file under the current directory, including subdirectories, and excluding the directories themselves. The interesting numbers are usually the breakdowns — by extension and by subfolder — and there is one case where wc -l lies to you: a filename containing a newline.

1. How many files in total

clai
$ clai how many files are in this folder and all subfolders→ find . -type f | wc -l20

-type f leaves out directories and symlinks, so the number means something. ls | wc -l in the same folder answers 3 — it only sees the top level and counts directories as entries.

2. Break it down by extension

clai
$ clai count the files by extension→ find . -type f -name '*.*' | sed 's/.*\.//' | sort | uniq -c | sort -rn      7 jpg      6 py      4 md      1 txt      1 png      1 bin

This is usually the question behind the question: what is this directory actually made of. -name '*.*' drops files with no extension — without it sed hands you the whole filename instead.

3. Break it down by subfolder

clai
$ clai count files in each subfolder→ for d in */; do printf '%5s %s\n' "$(find "$d" -type f | wc -l)" "$d"; done    3 docs/    8 img/    7 src/

A loop over the top-level directories, counting recursively inside each. Hidden directories don't match */, which is why these numbers add up to less than the total.

4. Without hidden files

clai
$ clai count files but skip hidden ones→ find . -type f -not -path '*/.*' | wc -l18

20 versus 18 — exactly the two dotfiles. -not -path '*/.*' also excludes everything inside hidden directories like .git, which is usually what you meant.

5. The trap: a newline in a filename

clai
$ clai count files reliably even if names contain newlines→ find . -type f -printf '.' | wc -c21

Tested with a file whose name spans two lines: find . -type f | wc -l reports 22 in the same directory. wc -l counts lines, not files. -printf '.' emits one dot per file and the count is right again. The portable version without GNU extensions is find . -type f -print0 | tr -dc '\0' | wc -c.

6. Files and directories in one line

clai
$ clai show how many files and how many directories are here→ printf 'files: %s\ndirs: %s\n' "$(find . -type f | wc -l)" "$(find . -type d | wc -l)"

-type d counts the current directory too, so the directory number is always one higher than you expect.

Gotchas

  • ls | wc -l counts the wrong thing. It never enters subdirectories, it does count directories, and it skips dotfiles. find -type f is the one that answers the question you asked.
  • wc -l breaks on newlines in filenames. Verified: 21 files, answer 22. When the directory came from somewhere else — users, an archive, a scraper — count with -printf '.' or -print0.
  • find . walks into hidden directories. In a repository .git alone can add thousands of files to your total. Filter with -not -path '*/.*' or the number means nothing.

Related questions

How do I count only the top level? find . -maxdepth 1 -type f | wc -l stays out of subdirectories.

How do I count one file type? find . -type f -name '*.log' | wc -l. Case matters; use -iname when it shouldn't.

What if I want size instead of count? du -sh . gives the total size, and du -h --max-depth=1 | sort -h breaks it down per subfolder.

See also

CliAI turns "how many files by type" into the whole pipeline, and shows it before it runs. Install it in one line.