Common Traps

WRONG — unquoted glob gets expanded by shell before find sees it
# WRONG — shell expands *.adoc to files in current directory
# find docs -name *.adoc

# CORRECT — quote the pattern so find handles the glob
find ~/atelier/_bibliotheca/domus-captures/docs -name "*.adoc" -type f | head -5
-print is implicit — until you use -exec or -delete
# This prints matching files (implicit -print)
find /etc -maxdepth 1 -name "*.conf" -type f 2>/dev/null | head -5

# But this prints NOTHING — -exec suppresses implicit -print
# find /etc -maxdepth 1 -name "*.conf" -exec grep -q "Port" {} \;

# CORRECT — add explicit -print after -exec with -o
find /etc -maxdepth 1 -name "*.conf" -type f \
  -exec grep -q "Port" {} \; -print 2>/dev/null | head -5
Symlinks — find does NOT follow them by default
# Default — does not follow symlinks (safer)
find /etc/alternatives -type f 2>/dev/null | head -5

# -L flag follows symlinks — needed when targets matter
find -L /etc/alternatives -type f 2>/dev/null | head -5
\; vs + — the performance trap
# SLOW — spawns one grep process per file found
find /etc -name "*.conf" -type f -exec grep -l "Port" {} \; 2>/dev/null

# FAST — spawns one grep process with all files as arguments
find /etc -name "*.conf" -type f -exec grep -l "Port" {} + 2>/dev/null
Operator precedence — -o without parentheses gives wrong results
# WRONG — this finds: (type f AND name *.adoc) OR (name *.yml, any type)
# The -type f only applies to the first condition
# find docs -type f -name "*.adoc" -o -name "*.yml"

# CORRECT — parentheses group the OR, -type f applies to both
find ~/atelier/_bibliotheca/domus-captures/docs \
  -type f \( -name "*.adoc" -o -name "*.yml" \) | head -10
-prune with -o — the mandatory -print
# WRONG — prune works but results include the pruned directory name
# find . -name .git -prune -o -name "*.adoc"

# CORRECT — add explicit -print to suppress pruned path in output
find ~/atelier/_bibliotheca/domus-captures \
  -name .git -prune -o -name "*.adoc" -type f -print | head -10
-delete evaluates left to right — order matters
# WRONG — deletes ALL files, then the -name check is pointless
# find /tmp -delete -name "*.tmp"

# CORRECT — predicates filter first, -delete acts on what remains
find /tmp -name "*.tmp" -type f -empty -delete 2>/dev/null
-name matches basename only, -path matches full path
# -name only matches the filename — this finds nothing
# find docs -name "codex/find" -type d

# -path matches the full relative path from the search root
find ~/atelier/_bibliotheca/domus-captures/docs -path "*/codex/find" -type d
Spaces in filenames — always use -print0 with xargs -0
# WRONG — breaks on filenames with spaces
# find /tmp -name "*.txt" | xargs wc -l

# CORRECT — null-delimited pipeline
cat <<'EOF' > "/tmp/file with spaces.txt"
hello world
EOF
find /tmp -name "file with*" -print0 | xargs -0 wc -l
Permission errors flood output — redirect stderr
# WRONG — permission denied messages obscure real results
# find / -name "*.conf" -type f

# CORRECT — suppress permission errors
find / -name "*.conf" -type f 2>/dev/null | head -10