find β File Search#
Syntax#
find [PATH...] [EXPRESSION]
Name and path filters#
find . -name "*.log" # glob match on filename
find . -iname "readme*" # case-insensitive
find . -path "*/src/*.ts" # match full path
find . -not -name "*.min.js" # exclude pattern
find . -name "*.py" -o -name "*.rb" # OR: .py or .rb
Type filters#
| Flag | Type |
|---|---|
-type f | regular file |
-type d | directory |
-type l | symlink |
-type p | named pipe |
-type s | socket |
-type b | block device |
-type c | character device |
find /tmp -type f # only files
find . -type d -name "__pycache__"
find /etc -type l # all symlinks in /etc
Size filters#
find . -size +10M # larger than 10 MB
find . -size -100k # smaller than 100 KB
find . -size +1G -type f # files over 1 GB
find . -empty # zero-byte files or empty dirs
# Units: c (bytes) k (KB) M (MB) G (GB)
Time filters#
find . -mtime -1 # modified within last 24 h
find . -mtime +30 # modified more than 30 days ago
find . -mtime 0 # modified today (0β24 h ago)
find . -newer /tmp/stamp # modified after the stamp file
find . -atime -7 # accessed within 7 days
find . -ctime -1 # inode changed within 24 h
# -mmin / -amin / -cmin for minutes instead of days
find . -mmin -60 # modified within last hour
Permission and ownership#
find . -perm 0644 # exactly 0644
find . -perm -0644 # at least these bits set
find . -perm /0111 # any execute bit set
find . -user alice # owned by alice
find . -group wheel # owned by wheel group
find . -not -user root # not owned by root
find /tmp -perm -1777 -type d # sticky-bit dirs (shared tmp)
Depth control#
find . -maxdepth 1 # only immediate children
find . -mindepth 2 -maxdepth 4 # depth 2β4 only
find . -maxdepth 0 # only the start path itself
Execute actions#
# {} is replaced by the current file path
find . -name "*.tmp" -exec rm {} \; # delete one at a time
find . -name "*.sh" -exec chmod +x {} \; # make executable
find . -type f -exec wc -l {} + # batch with + (faster)
# execdir β run command in the file's directory
find . -name "*.py" -execdir python -m py_compile {} \;
# Print with format
find . -name "*.log" -printf "%p\t%s\n" # path + size (bytes)
find . -type f -printf "%T@ %p\n" | sort -n # sort by mtime
Delete#
find . -name "*.pyc" -delete # delete matching files
find . -type d -name __pycache__ -delete # delete matching dirs
# -delete implies -depth; use with care
Prune (skip directories)#
# Skip .git and node_modules
find . -name ".git" -prune -o -name "node_modules" -prune -o \
-name "*.js" -print
# General pattern: -path SKIP -prune -o EXPR -print
find . \( -path "./.git" -o -path "./dist" \) -prune \
-o -type f -name "*.md" -print
Logical operators#
| Operator | Syntax |
|---|---|
| AND (default) | -a or nothing |
| OR | -o |
| NOT | ! or -not |
| Grouping | \( ... \) |
find . \( -name "*.jpg" -o -name "*.png" \) -size +1M
find . -not \( -name "*.py" -o -name "*.sh" \)
Practical recipes#
# Top 10 largest files
find . -type f -printf "%s\t%p\n" | sort -rn | head -10
# Find files modified in the last 5 minutes (useful post-install)
find / -type f -newer /tmp/before -mmin -5 2>/dev/null
# Broken symlinks
find . -type l ! -exec test -e {} \; -print
# World-writable files (security audit)
find / -xdev -type f -perm -0002 2>/dev/null
# SUID/SGID binaries
find / -xdev \( -perm -4000 -o -perm -2000 \) -type f 2>/dev/null
# Find and compress logs older than 7 days
find /var/log -name "*.log" -mtime +7 -exec gzip {} \;
# Delete empty directories
find . -type d -empty -delete
# Replace string in all matched files (with sed)
find . -name "*.conf" -exec sed -i 's/oldhost/newhost/g' {} +
# Count files per extension
find . -type f | sed 's/.*\.//' | sort | uniq -c | sort -rn
# Find duplicate filenames (different paths)
find . -type f -printf "%f\n" | sort | uniq -d
Cross-filesystem#
find / -xdev -name "*.core" # don't cross mount boundaries
find / -mount -name "lost+found"
[!TIP] Use
find ... -exec cmd {} +(plus sign) instead of\;(semicolon) when possible. The+variant batches many filenames into a singlecmdcall, likexargs, and can be 10β100Γ faster on large result sets.
[!WARN]
-deletesilently follows-depthorder (deepest first). Test your expression with-delete.