You need to find all Python files modified in the last week. You google it. You find the answer. You use it. Next week, you’ve forgotten it again.
find is powerful but arcane. Here are the patterns you actually use.
The Basics
Find all files in a directory:
find /path/to/search -type fType flags:
-type f— Regular files-type d— Directories-type l— Symlinks-type s— Sockets-type p— Named pipes
By Time: -mtime, -atime, -ctime
-mtime N — Modified N days ago (exactly)
# Modified exactly 3 days agofind . -mtime 3
# Modified 3 or more days agofind . -mtime +3
# Modified within the last 3 daysfind . -mtime -3-mmin — Minutes instead of days
# Modified in the last 30 minutesfind . -mmin -30-atime — Last accessed
# Last accessed 7+ days ago (great for cleanup)find . -atime +7-newer — Compared to another file’s timestamp
# Modified after 2024-01-01 (use a reference file)touch -d '2024-01-01' /tmp/reffind . -newer /tmp/ref
# Or compare to another file:find . -newer /path/to/other/fileBy Size: -size
# Exactly 100 bytesfind . -size 100c
# More than 1MBfind . -size +1M
# Less than 10KBfind . -size -10k
# Between 1MB and 100MBfind . -size +1M -size -100MSize units:
c— bytesk— kilobytesM— megabytesG— gigabytesb— 512-byte blocks
By Name: -name, -iname
# Exact name matchfind . -name "*.py"
# Case-insensitivefind . -iname "*.PY"
# Any file starting with "test"find . -name "test*"
# Multiple patterns (OR logic)find . \( -name "*.py" -o -name "*.pyc" \)Negation: -not
# All files except .gitfind . -not -path "./.git/*"
# All Python files except __pycache__find . -name "*.py" -not -path "*/__pycache__/*"
# All files newer than 7 days, except directoriesfind . -type f -mtime -7 -not -name ".git"Execution: -exec vs xargs
-exec — Run a command on each result
# Delete all .tmp filesfind . -name "*.tmp" -exec rm {} \;
# Print full path with lsfind . -type f -name "*.py" -exec ls -lh {} \;
# Multiple commands with bashfind . -type f -exec bash -c 'echo "File: {}"; wc -l "{}"' \;The {} is replaced with the filename. The \; ends the command.
-exec with + instead of ; — More efficient
# Pass multiple files at once (like xargs)find . -name "*.py" -exec wc -l {} +# Runs: wc -l file1.py file2.py file3.py (all at once)
# Instead of:find . -name "*.py" -exec wc -l {} \;# Runs: wc -l file1.py, then wc -l file2.py, then wc -l file3.py (one at a time)xargs — Pipe results to another command
# Find all .log files and delete themfind . -name "*.log" | xargs rm
# Count lines in all Python filesfind . -name "*.py" | xargs wc -l
# Be careful with spaces in filenames, use null delimiter:find . -name "*.py" -print0 | xargs -0 wc -lWhen to use what:
-execfor simple commands on individual files-exec ... +when the command accepts multiple argumentsxargswhen you’re piping to another tool
Practical Patterns
Find all files modified today
find . -type f -mtime 0Find and delete old backup files
find /backups -name "*.bak" -mtime +30 -exec rm {} \;Find all symlinks pointing to nonexistent targets
find . -type l ! -exec test -e {} \; -printFind all Python files in a project and count total lines
find . -name "*.py" -not -path "./venv/*" -not -path "./.git/*" | xargs wc -l | tail -1Find all files owned by a specific user
find . -user alice -type fFind files created/modified within a specific time range
# Modified in the last 2 days but not in the last 1 dayfind . -type f -mtime -2 -mtime +1
# Or using -newermt (GNU find):find . -type f -newermt "2025-03-20" -not -newermt "2025-03-24"Recursively find and replace in files
find . -name "*.py" -type f -exec sed -i 's/old_text/new_text/g' {} \;Find all executable files
find . -type f -executableFind and copy files matching a pattern
find /source -name "*.jpg" -exec cp {} /destination \;Find large files taking up disk space
find . -type f -size +100M -exec ls -lh {} \; | sort -k5 -hrFind files with specific permissions
# World-writable files (security risk)find . -type f -perm -002
# Files with setuid bitfind . -type f -perm -4000A Real-World Script
Clean up old log files and Docker build cache:
#!/bin/bash
# Remove logs older than 30 daysfind /var/log -type f -mtime +30 -exec rm {} \;
# Remove docker build cache older than 7 daysfind /var/lib/docker/containers -type f -mtime +7 -name "*.log" -exec truncate -s 0 {} \;
# Find any Python cache taking up spacefind . -type d -name "__pycache__" -exec rm -rf {} \; 2>/dev/null || truefind is one of those tools that pays off. Spend an hour memorizing these patterns and you’ll save that back in the next month. Your 2 AM self will thank you when you know exactly how to find those rogue log files eating your disk.