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.
Basic Search
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 2find <path> -mindepth <n> — Skip the first n levels and only return results deeper than that.
find . -mindepth 2find <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 lfind <path> -type f -empty — Find empty files (zero bytes).
find /tmp -type f -emptyfind <path> -type d -empty — Find empty directories.
find . -type d -emptySearch by Size
find <path> -size +<n>M — Find files larger than n megabytes.
find / -size +100Mfind <path> -size -<n>k — Find files smaller than n kilobytes.
find . -size -10kfind <path> -size <n>c — Find files of exactly n bytes.
find . -size 0cfind <path> -size +<n>G — Find files larger than n gigabytes.
find / -type f -size +1Gfind <path> -size +<min>M -size -<max>M — Find files within a size range.
find . -type f -size +10M -size -100MSearch by Time
find <path> -mtime -<n> — Find files modified in the last n days.
find . -mtime -7find <path> -mtime +<n> — Find files modified more than n days ago.
find /var/log -mtime +30find <path> -mmin -<n> — Find files modified in the last n minutes.
find . -mmin -60find <path> -atime -<n> — Find files accessed in the last n days.
find . -atime -7find <path> -ctime -<n> — Find files whose status (metadata) changed in the last n days.
find . -ctime -1find <path> -newer <reference> — Find files modified more recently than a reference file.
find . -newer /tmp/timestamp.txtfind <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 644find <path> -perm -<mode> — Find files where all specified permission bits are set.
find . -perm -u+xfind <path> -perm /<mode> — Find files where any of the specified permission bits are set.
find . -perm /o+wfind <path> -user <username> — Find files owned by a specific user.
find /home -user www-datafind <path> -group <groupname> — Find files belonging to a specific group.
find /var -group stafffind <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 ffind <path> -perm -2000 — Find files with the SGID bit set.
find /usr -perm -2000 -type fActions
find <path> <expression> -print — Print the full path of each match (default action).
find . -name '*.log' -printfind <path> <expression> -print0 — Print results separated by null character (safe for filenames with spaces).
find . -name '*.txt' -print0 | xargs -0 wc -lfind <path> <expression> -ls — Print results in ls -l format with detailed file info.
find /tmp -type f -mtime -1 -lsfind <path> <expression> -delete — Delete all matching files (use with caution, test with -print first).
find /tmp -type f -name '*.tmp' -mtime +7 -deletefind <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 +100kfind <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 +10kOutput & 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 -20find <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 -10find <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' -printfind <path> -path '<pattern>' -prune -o <expression> -print — Exclude directories matching a path pattern.
find . -path './.git' -prune -o -type f -printfind <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' -printPractical 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
- GNU Findutils Manual – complete official reference for all find options
- find(1) manual page – the Linux manual page for find