find — Search Files and Directories in a Directory Tree

Practical guide to find — search files and directories by name, type, size, time and permissions, and act on the matches directly.

find walks entire directory trees and filters files and directories by name, type, size, timestamp, permissions and much more – and then acts on the matches directly. Instead of only printing paths, you attach arbitrary actions via -exec, -delete or a pipe to xargs. That is exactly where the tool gets sharp: find … -delete and find … -exec rm delete recursively and irreversibly, so test every destructive search with -print first. For filenames containing spaces or special characters, protect yourself with -print0 | xargs -0 or -exec … {} +. This guide walks you through the expressions you actually reach for daily, from a simple name search to filtered bulk processing.

find <path> — List all files and directories recursively under the given path.

find /home/user/projects/

find . — List all files and directories recursively under the current directory.

find <path> -maxdepth <n> — Limit the search depth to n levels below the starting point.

find . -maxdepth 2

find <path> -mindepth <n> — Skip the first n levels and only return results deeper than that.

find . -mindepth 2

find <path1> <path2> — Search in multiple directories at once.

find /var/log /tmp -name '*.log'

Search by Name

find <path> -name '<pattern>' — Find files matching a name pattern (case-sensitive, supports wildcards).

find . -name '*.js'

find <path> -iname '<pattern>' — Find files matching a name pattern (case-insensitive).

find . -iname '*.jpg'

find <path> -name '<pattern>' -not -name '<pattern>' — Find files matching one pattern but not another.

find . -name '*.js' -not -name '*.min.js'

find <path> -path '<pattern>' — Match against the full path, not just the filename.

find . -path '*/src/*.ts'

find <path> -regex '<pattern>' — Match filenames using a regular expression (matches the whole path).

find . -regex '.*\.(js\|ts)$'

find <path> -iregex '<pattern>' — Match filenames using a case-insensitive regular expression.

find . -iregex '.*\.jpe?g$'

Search by Type

find <path> -type f — Find regular files only.

find /var/log -type f -name '*.log'

find <path> -type d — Find directories only.

find . -type d -name 'node_modules'

find <path> -type l — Find symbolic links only.

find /usr/bin -type l

find <path> -type f -empty — Find empty files (zero bytes).

find /tmp -type f -empty

find <path> -type d -empty — Find empty directories.

find . -type d -empty

Search by Size

find <path> -size +<n>M — Find files larger than n megabytes.

find / -size +100M

find <path> -size -<n>k — Find files smaller than n kilobytes.

find . -size -10k

find <path> -size <n>c — Find files of exactly n bytes.

find . -size 0c

find <path> -size +<n>G — Find files larger than n gigabytes.

find / -type f -size +1G

find <path> -size +<min>M -size -<max>M — Find files within a size range.

find . -type f -size +10M -size -100M

Search by Time

find <path> -mtime -<n> — Find files modified in the last n days.

find . -mtime -7

find <path> -mtime +<n> — Find files modified more than n days ago.

find /var/log -mtime +30

find <path> -mmin -<n> — Find files modified in the last n minutes.

find . -mmin -60

find <path> -atime -<n> — Find files accessed in the last n days.

find . -atime -7

find <path> -ctime -<n> — Find files whose status (metadata) changed in the last n days.

find . -ctime -1

find <path> -newer <reference> — Find files modified more recently than a reference file.

find . -newer /tmp/timestamp.txt

find <path> -newermt '<date>' — Find files modified after a specific date (GNU find).

find . -newermt '2025-01-01'

find <path> -not -newermt '<date>' — Find files modified before a specific date.

find . -type f -not -newermt '2024-06-01'

Search by Permissions & Ownership

find <path> -perm <mode> — Find files with exactly the specified permissions.

find . -perm 644

find <path> -perm -<mode> — Find files where all specified permission bits are set.

find . -perm -u+x

find <path> -perm /<mode> — Find files where any of the specified permission bits are set.

find . -perm /o+w

find <path> -user <username> — Find files owned by a specific user.

find /home -user www-data

find <path> -group <groupname> — Find files belonging to a specific group.

find /var -group staff

find <path> -nouser — Find files not owned by any known user.

find <path> -nogroup — Find files not belonging to any known group.

find <path> -perm -4000 — Find files with the SUID bit set.

find /usr -perm -4000 -type f

find <path> -perm -2000 — Find files with the SGID bit set.

find /usr -perm -2000 -type f

Actions

find <path> <expression> -print — Print the full path of each match (default action).

find . -name '*.log' -print

find <path> <expression> -print0 — Print results separated by null character (safe for filenames with spaces).

find . -name '*.txt' -print0 | xargs -0 wc -l

find <path> <expression> -ls — Print results in ls -l format with detailed file info.

find /tmp -type f -mtime -1 -ls

find <path> <expression> -delete — Delete all matching files (use with caution, test with -print first).

find /tmp -type f -name '*.tmp' -mtime +7 -delete

find <path> <expression> -exec <command> {} \; — Execute a command for each match. {} is replaced by the filename.

find . -name '*.log' -exec rm {} \;

find <path> <expression> -exec <command> {} + — Execute a command with all matches as arguments (faster than ;).

find . -name '*.txt' -exec grep -l 'TODO' {} +

find <path> <expression> -execdir <command> {} \; — Execute a command in the directory of each match (safer than -exec).

find . -name '*.bak' -execdir rm {} \;

find <path> <expression> -ok <command> {} \; — Like -exec but ask for confirmation before each execution.

find . -name '*.tmp' -ok rm {} \;

Logical Operators

find <path> -name '<a>' -and -name '<b>' — Match files satisfying both conditions (AND, default when juxtaposed).

find . -name '*.js' -and -size +100k

find <path> -name '<a>' -or -name '<b>' — Match files satisfying either condition (OR).

find . -name '*.jpg' -or -name '*.png'

find <path> -not <expression> — Negate an expression (NOT).

find . -type f -not -name '*.log'

find <path> \( <expr1> -or <expr2> \) -and <expr3> — Group expressions with escaped parentheses for precedence.

find . \( -name '*.js' -or -name '*.ts' \) -and -size +10k

Output & Formatting

find <path> -printf '<format>' — Print results in a custom format (GNU find).

find . -type f -printf '%s %p\n'

find <path> -printf '%T+ %p\n' — Print modification time and path for each file.

find . -type f -printf '%T+ %p\n' | sort -r | head -20

find <path> -printf '%s\t%p\n' — Print file size (bytes) and path, tab-separated.

find . -type f -printf '%s\t%p\n' | sort -rn | head -10

find <path> -fprintf <file> '<format>' — Write formatted output to a file instead of stdout.

find /var/log -type f -fprintf /tmp/logfiles.txt '%p\n'

Excluding Directories

find <path> -name '<dir>' -prune -o <expression> -print — Exclude a directory from the search using -prune.

find . -name 'node_modules' -prune -o -name '*.js' -print

find <path> -path '<pattern>' -prune -o <expression> -print — Exclude directories matching a path pattern.

find . -path './.git' -prune -o -type f -print

find <path> \( -name '<a>' -o -name '<b>' \) -prune -o <expression> -print — Exclude multiple directories from the search.

find . \( -name 'node_modules' -o -name '.git' \) -prune -o -type f -name '*.ts' -print

Practical Examples

find . -type f -name '*.log' -mtime +30 -delete — Delete log files older than 30 days.

find . -type f -name '*.php' -exec grep -l '<pattern>' {} + — Find PHP files containing a specific string.

find . -type f -name '*.php' -exec grep -l 'TODO' {} +

find . -type f -exec chmod 644 {} + — Set permissions to 644 for all regular files.

find . -type d -exec chmod 755 {} + — Set permissions to 755 for all directories.

find . -type f -name '*.txt' -print0 | xargs -0 tar -czf texts.tar.gz — Create a tar archive of all .txt files (handles spaces in names).

find . -type f -printf '%s\t%p\n' | sort -rn | head -20 — Find the 20 largest files in a directory tree.

find . -type f -name '*.jpg' -exec cp {} /backup/images/ \; — Copy all JPEG files to a backup directory.

find . -maxdepth 1 -type f -name '*.bak' -exec mv {} {}.old \; — Rename all .bak files by appending .old in the current directory.

find . -name '*.orig' -o -name '*.bak' -o -name '*~' | xargs rm -f — Remove common backup and temporary files.

find /var/log -type f -size +50M -exec ls -lh {} + — List large log files with human-readable sizes.

Conclusion

find is one of the most powerful tools on the command line: with combinable tests for name, type, size, time and permissions, you narrow down even huge directory trees precisely and process the matches in one pass. That same power makes find dangerous, though – -delete and -exec rm … {} + delete recursively and without asking; test every destructive search with -print first, and for filenames with spaces use -print0 | xargs -0 or -exec … {} + consistently rather than a plain pipe. Note as well that -printf/-fprintf, -regex and -newermt are GNU extensions: the find on macOS and BSD does not know -printf and behaves differently for some options.

Further Reading

  • grep – searches file contents for patterns and regular expressions
  • xargs – builds and runs command lines from find's output
  • ls – lists directory contents with details on permissions and size