find
find walks a directory tree, matching by name, size, time, permissions, owner. With -exec or -print0 | xargs it’s a one-liner Swiss-army knife.
find + exec, real recipes
EXAMPLE
# 1) Basics
find . # everything under cwd
find /etc -name '*.conf' # by name (glob)
find . -iname '*readme*' # case-insensitive
find . -path '*/test/*' # match path segment
find . -not -path './.git/*' # exclude git
# 2) By type
find . -type f # files only
find . -type d # directories only
find . -type l # symlinks
# 3) By size
find / -size +100M # > 100 MiB
find . -size -1k # < 1 KiB
find . -empty # empty files / dirs
# 4) By time — minutes / days / mtime / ctime / atime
find . -mtime -1 # modified < 1 day ago
find . -mtime +30 # modified > 30 days ago
find . -mmin -5 # modified in last 5 min
find . -newer reference.txt # modified after this file
# 5) By permissions / owner
find / -perm -4000 # SUID files (audit target)
find . -user ada # owned by ada
find . -group developers
find . -perm /u+w # writable by owner
# 6) Combine with logical operators
find . -type f \( -name '*.log' -o -name '*.tmp' \)
find . -type f -name '*.js' -not -path './node_modules/*'
# 7) Act on matches — -exec ; vs +
find . -name '*.tmp' -exec rm {} \; # one per file (slow)
find . -name '*.tmp' -exec rm {} + # batched (fast)
find . -name '*.log' -exec gzip {} \;
find . -type f -name '*.txt' -exec grep -l 'TODO' {} +
# 8) Pipe safely with xargs (handles spaces / newlines)
find . -type f -name '*.png' -print0 | xargs -0 du -h | sort -h
find . -type f -name '*.ts' -print0 | xargs -0 wc -l | tail -1
# 9) Parallel processing
find . -name '*.jpg' -print0 | xargs -0 -P 8 -I {} convert {} -resize 800x600 {}-small.jpg
# 10) Common real recipes
# - Files modified by you in the last day
find . -user "$USER" -mtime -1 -type f
# - Biggest files in a directory
find . -type f -printf '%s %p\n' | sort -nr | head
# - Find files containing TODO with grep -l
find src -type f -name '*.go' -exec grep -l TODO {} +
# - Delete __pycache__ everywhere
find . -type d -name __pycache__ -exec rm -rf {} +
# - Find broken symlinks
find . -xtype l
# - Files with no group / no owner (often left after user deletion)
find / -nouser -o -nogroup 2>/dev/null
# - Files of a specific extension, newest first
find . -name '*.md' -printf '%T@ %p\n' | sort -rn | head
# 11) Modern alternative — fd
# fd 'pattern' # like find but smart defaults
# fd -e ts # files with extension ts
# fd -H 'config' # include hidden files
# 12) Performance
# • Prune unwanted directories early
# find . -path ./node_modules -prune -o -type f -name '*.js' -print
# • Combine -exec ... + over ... \;
# • Use locate / mlocate when the index is fresh — milliseconds vs seconds
Why it matters
Reach for -exec ... + (or -print0 | xargs -0) over -exec ... \; — one process per batch instead of per file. On a 10k-file find, the speedup is 100×.
Tip: Tweak the snippet with Try it Yourself », then sit the quiz at the bottom of the page.
Discussion
Loading…