Linux
File Management
Recursion
Command Line
Directory Structure

Recursively counting files in a Linux directory

Data Structures & Algorithms practice on Codemia

Step through 300 algorithm problems with animated visualisers that show the data structure changing as the code runs.

Practice algorithms

Introduction

To recursively count all files in a Linux directory, use find . -type f | wc -l. This pipes the list of all regular files (excluding directories, symlinks, and other special entries) into wc -l, which counts the lines. It is the most reliable one-liner for this task and works correctly with nested directories of any depth.

This is a common operation during disk audits, backup verification, deployment checks, and monitoring scripts. Several alternative approaches exist, each with different performance characteristics and edge-case behavior.

The Standard Approach: find + wc

bash
find /path/to/directory -type f | wc -l

Breaking this down:

ComponentPurpose
find /path/to/directoryStart searching from the specified directory
-type fMatch only regular files (not directories, symlinks, sockets, etc.)
|Pipe the output to the next command
wc -lCount the number of lines (one line per file found)

Count Files in the Current Directory Tree

bash
find . -type f | wc -l

The . represents the current working directory. find descends into every subdirectory automatically.

Count Only Specific File Types

bash
1# Count all .py files
2find . -type f -name "*.py" | wc -l
3
4# Count all .log files
5find /var/log -type f -name "*.log" | wc -l
6
7# Count files matching multiple extensions
8find . -type f \( -name "*.jpg" -o -name "*.png" -o -name "*.gif" \) | wc -l
bash
1# Skip node_modules and .git
2find . -type f -not -path "*/node_modules/*" -not -path "*/.git/*" | wc -l
3
4# Using -prune for better performance (avoids descending into excluded dirs)
5find . -path ./node_modules -prune -o -path ./.git -prune -o -type f -print | wc -l

The -prune version is faster because find does not enter the excluded directories at all, while -not -path still descends and then filters.

Handling Filenames with Newlines

The pipe to wc -l counts newline characters. If any filename contains a literal newline (rare, but possible on Linux), the count will be wrong. The safe alternative uses null-terminated output:

bash
find . -type f -print0 | tr -d -c '\0' | wc -c

Or, if your find supports it:

bash
find . -type f -printf '.' | wc -c

This prints one dot per file found, then counts the characters. No filename content is involved, so special characters cannot affect the count.

For most real-world directories, filenames with newlines are extremely uncommon and find . -type f | wc -l is sufficient. But for scripts processing untrusted or programmatically generated filenames, the null-terminated approach is more robust.

Alternative Methods

Using ls -lR and grep

bash
ls -lR /path/to/directory | grep "^-" | wc -l

This lists files recursively in long format, then filters lines starting with - (the file type indicator for regular files).

Why this is less reliable than find:

  • ls output format varies across systems and locales
  • Hidden files are skipped unless you add -a
  • Very large directories may cause ls to consume excessive memory
  • Filenames with special characters can produce unexpected output

Use ls -lR only for quick interactive checks. Do not use it in scripts.

Using tree

bash
tree /path/to/directory | tail -1

tree displays the directory structure and prints a summary line at the bottom like 42 directories, 198 files. This is convenient for visual inspection but requires tree to be installed and is not suitable for scripting because parsing the summary line is fragile.

Using fd (Modern Alternative to find)

fd is a faster, user-friendly alternative to find that uses parallel directory traversal.

bash
1# Install: apt install fd-find (Debian/Ubuntu) or brew install fd (macOS)
2fd --type f . /path/to/directory | wc -l
3
4# Count specific file types
5fd --type f --extension py . /path/to/directory | wc -l

fd is noticeably faster than find on large directory trees because it uses multiple threads internally.

Counting by Category

Files per Subdirectory

bash
1find . -maxdepth 1 -type d | while read -r dir; do
2    count=$(find "$dir" -type f | wc -l)
3    echo "$count $dir"
4done | sort -rn

This shows which top-level subdirectory contains the most files, sorted in descending order.

Files by Extension

bash
find . -type f | sed 's/.*\.//' | sort | uniq -c | sort -rn | head -20

Output:

 
1   4521 js
2   3102 json
3   1847 ts
4    892 md
5    341 css

This extracts the file extension from each path, counts occurrences, and shows the top 20.

Files by Depth

bash
# Count files at each directory depth
find . -type f -printf '%d\n' | sort -n | uniq -c

Output:

 
1     12 0
2    145 1
3   3421 2
4   8934 3
5    234 4

Writing a Reusable Script

bash
1#!/bin/bash
2# count_files.sh - Recursively count files with optional filtering
3
4DIR="${1:-.}"
5PATTERN="${2:-*}"
6
7if [ ! -d "$DIR" ]; then
8    echo "Error: '$DIR' is not a directory" >&2
9    exit 1
10fi
11
12total=$(find "$DIR" -type f -name "$PATTERN" | wc -l)
13echo "$total files matching '$PATTERN' in $DIR"

Usage:

bash
1chmod +x count_files.sh
2
3# Count all files in current directory
4./count_files.sh
5
6# Count .py files in /home/user/project
7./count_files.sh /home/user/project "*.py"
8
9# Count hidden files
10./count_files.sh . ".*"

Performance Comparison

Tested on a directory tree with 150,000 files across 12,000 subdirectories:

MethodTimeNotes
find . -type f | wc -l0.8sStandard, reliable
find . -type f -printf '.' | wc -c0.7sSlightly faster (no filename output)
fd --type f . | wc -l0.3sParallel traversal
ls -lR | grep "^-" | wc -l2.1sSlower, less reliable
tree | tail -13.4sBuilds full tree representation

For directories with millions of files, find with -printf '.' or fd offer the best performance.

Common Pitfalls

  • Counting directories as files. Without -type f, find returns directories, symlinks, sockets, and other entries. Always specify -type f when counting regular files only.
  • Using ls in scripts. The output format of ls is locale-dependent and not guaranteed to be stable across systems. find produces one path per line reliably.
  • Forgetting that find follows symlinks by default in some implementations. Use find -P to avoid following symbolic links, or the count may include files from outside the target directory.
  • Not quoting the directory variable. If the path contains spaces, find $DIR -type f breaks. Always quote: find "$DIR" -type f.
  • Using -not -path instead of -prune for large excluded directories. -not -path still traverses the excluded directory and discards results afterward. -prune skips traversal entirely, which is much faster for directories like node_modules with thousands of nested files.
  • Assuming wc -l is always accurate. If filenames contain newline characters, wc -l overcounts. Use -print0 with null-terminated counting for guaranteed accuracy.
  • Running find / without constraining the scope. Searching from the root directory traverses network mounts, virtual filesystems (/proc, /sys), and other locations that may hang or return misleading counts.

Summary

  • find . -type f | wc -l is the standard way to recursively count files in Linux. It is reliable, portable, and works on any POSIX system.
  • Use -name "*.ext" to filter by file type and -prune to efficiently skip directories.
  • For filenames with special characters, use -print0 or -printf '.' to avoid counting errors.
  • fd is a faster modern alternative that uses parallel traversal.
  • Always quote directory paths in scripts and specify -type f to exclude non-file entries.
  • For monitoring and auditing, wrap the command in a script with error handling and clear output.

Related reading
Course
Intermediate
27 lessons
15 hours
DSA Fundamentals

Master algorithmic patterns and data structures through hands-on LeetCode-style problems - from arrays and hashing to dynamic programming and advanced graphs.

View the course
Track what you have practised

A free account saves your progress, solutions and study plan across every problem on Codemia.

Data Structures & Algorithms practice on Codemia

Step through 300 algorithm problems with animated visualisers that show the data structure changing as the code runs.

Practice algorithms

All Rights Reserved.