Search for files and directories by name, type, size, time, permissions, and more.
find walks a directory tree and evaluates each file or directory against tests you specify. When something matches, it can print the path, run an action, delete it, or pass it to another command.
-print, -delete, or -exec# Find a file by exact name in current directory tree find . -name "notes.txt" # Find directories only find . -type d # Find files only find . -type f
-name "PATTERN" Match name (case-sensitive)
-iname "PATTERN" Match name (case-insensitive)
-type f Files only
-type d Directories only
-type l Symlinks only
-size +100M Larger than 100 MB
-size -10k Smaller than 10 KB
-mtime -7 Modified within last 7 days
-mtime +30 Modified more than 30 days ago
-user USER Owned by user
-group GROUP Owned by group
-perm 644 Exact permissions
-perm -u+w Has writable bit for user
-maxdepth N Limit recursion depth
-mindepth N Skip top levels
-empty Empty files or directories
-delete Delete matched items
-print Print matched paths
-exec CMD {} \; Run command once per match
-exec CMD {} + Run command with many matches at once
# OR logic find . \( -name "*.log" -o -name "*.tmp" \) # AND logic (implicit) find . -type f -name "*.txt" # NOT logic find . ! -name "*.txt" # Case-insensitive name match find . -iname "*report*"
Important: parentheses usually need escaping in the shell: \( and \).
# 1) Find a specific file by name find . -name "config.yaml"
# 2) Find all .txt files find . -type f -name "*.txt"
# 3) Find directories named cache find . -type d -name "cache"
# 4) Case-insensitive search find . -iname "*invoice*"
# 5) Find files bigger than 500 MB find . -type f -size +500M
# 6) Find files modified in last 2 days find . -type f -mtime -2
# 7) Find files older than 30 days find . -type f -mtime +30
# 8) Find empty files find . -type f -empty
# 9) Find empty directories find . -type d -empty
# 10) Find by permissions find . -type f -perm 644
# 11) Find and delete .tmp files find . -type f -name "*.tmp" -delete
# 12) Find and run a command on matches
find . -type f -name "*.log" -exec ls -lh {} \;# Find files and search inside them with grep
find . -type f -name "*.txt" -exec grep -H "ERROR" {} \;# Better for many files: use grep directly if it supports recursion grep -r "ERROR" .
# Find all shell scripts find . -type f -name "*.sh"
# Find broken symlinks find . -xtype l
# Limit search depth find . -maxdepth 2 -type f
# Skip the top directory itself find . -mindepth 1 -type d
# Find files owned by a user find /var/www -user apache
# Find world-writable files find . -type f -perm -0002
# Find then remove empty directories find . -type d -empty -delete
# Find and copy results elsewhere using xargs
find . -type f -name "*.conf" | xargs -I{} cp "{}" /tmp/config-backup/-delete is powerful and dangerous. Test first with -print.-name matches only the filename, not the full path."*.log" so the shell does not expand them first.-exec ... {} \; runs once per file; -exec ... {} + is often faster./ may produce many permission-denied messages unless run with sudo or redirected.find and BSD/macOS find are similar but not identical in every option.# SAFEST workflow: # 1) print matches first find . -type f -name "*.tmp" -print # 2) only then delete find . -type f -name "*.tmp" -delete
That one habit prevents a lot of pain.
find has been a core Unix tool for decades. It became essential because Unix systems treat nearly everything as files, and administrators needed a precise way to search large directory trees and act on the results.
Modern tools like fd offer simpler syntax and faster defaults for common searches, but find remains the standard because it is widely available and far more powerful for complex filtering and actions.