find Command Builder
Build find commands by name, type, size, mtime and -exec/-delete actions.
find in depth: tests, actions, and the operators that glue them together
find is the canonical Unix walker — a POSIX utility older than most programming languages still in daily use. The general shape of a find command is find [paths...] [tests] [actions]: paths say where to look, tests filter the candidates, and actions say what to do with the matches. If no action is given, find behaves as if you wrote -print. This generator stitches together the most common tests; the sections below explain everything else you may want to add by hand.
Unlike ls, find walks the tree depth-first and evaluates each entry against the expression. Tests and actions are not separate phases — they are primaries that return true/false, joined by implicit AND. Once you internalize that, exotic-looking commands like find . -name '*.log' -mtime +30 -delete stop being magic: it is a logical AND of three primaries.
The most common tests
-name 'pattern'— shell glob on the basename only. Case-sensitive. Always quote the pattern so the shell does not expand it first.-iname 'pattern'— case-insensitive variant of-name.-path 'pattern'/-wholename— glob over the full relative path (great for "files under**/test/**").-type— file kind:fregular file,ddirectory,lsymlink,bblock device,cchar device,pnamed pipe (FIFO),ssocket.-size— file size. Suffixes:cbytes,kKiB,MMiB,GGiB. Prefix+/-for greater/less than. Example:-size +100M,-size -1k.-mtime N— modified N*24 h ago.-mtime -7= within the last 7 days,-mtime +30= older than 30 days. Same family:-atime(accessed) and-ctime(inode changed).-mmin N— same idea but in minutes (-mmin -60= touched in the last hour).-perm 644— exact mode match.-perm -u+w= at least user-write set.-perm /u+x,g+x= any of those bits set.-user name,-group name— match ownership.-empty— empty regular files and directories.-newer file— modified more recently thanfile. Handy for incremental builds.
Logical operators and grouping
Tests are AND-ed by default. Use -or (or -o) for OR and -not (or !) for negation. Group with escaped parentheses, because parentheses are shell metacharacters:
# All .bak OR .tmp files, then delete them
find . \( -name '*.bak' -o -name '*.tmp' \) -delete
# Regular files NOT under node_modules
find . -type f ! -path '*/node_modules/*'
For excluding whole directories without descending into them, prefer -prune over !: it stops find from walking the subtree, which is dramatically faster on big trees: find . -type d -name node_modules -prune -o -type f -print.
Actions: -print, -delete, -exec, and xargs
-print— default. One match per line, newline-terminated. Breaks on filenames containing newlines.-print0— NUL-separated output, designed forxargs -0. Safe against weird filenames.-delete— remove matches. No prompt, no recycle bin. Run with-printfirst.-exec cmd {} \;— runscmdonce per match. Portable, slow on big result sets because of fork overhead.-exec cmd {} +— batches matches into one invocation, much faster. Closer to what xargs would do.-ok cmd {} \;— like-execbut prompts before each invocation. Useful for destructive ops.
# Delete logs older than 30 days
find /var/log -name '*.log' -mtime +30 -delete
# Grep across files safely (handles spaces, newlines)
find . -type f -print0 | xargs -0 grep -l "TODO"
# Find suid binaries (security audit)
find / -perm -4000 -type f 2>/dev/null
# Total size of all .mp4 files
find . -name '*.mp4' -print0 | du -ch --files0-from=- | tail -1
find vs the modern alternatives
- fd (fd-find) — Rust rewrite focused on ergonomics: smart-case, gitignore-aware, parallel, colorful.
fd '\.log$'beatsfind . -name '*.log'in 90% of interactive uses. - ripgrep (rg) — when you actually want to grep file contents, rg is one to two orders of magnitude faster than
find ... | xargs grep. - locate / mlocate / plocate — query a pre-built filesystem index. Instant, but the index is only as fresh as the last
updatedbrun. - eza / exa — modern
lswith tree output and git status; not a search tool but often what people actually need.
FAQ
Why is find slow on huge trees? It walks every inode and has no index. For repeated queries on the same tree, build an index with updatedb and use locate, or switch to fd which parallelizes the walk.
-exec {} + or pipe to xargs — which is faster? Both batch matches into fewer invocations and end up within a few percent of each other. xargs -0 with -print0 is more flexible (parallelism with -P, custom placement of {}); -exec ... + is more portable and has no quoting issues.
How do I match case-insensitively? Use -iname, -ipath, -iregex. They are GNU extensions but supported in macOS BSD find as well.
Why does find . -name *.txt fail with "paths must precede expression"? The shell expanded *.txt into the matching filenames in the current directory before find ever saw it. Quote the pattern: find . -name '*.txt'.
What is the difference between -name and -path? -name matches only the basename (last segment); -path matches the entire relative path. To match "any .js under src/", use -path '*/src/*' -name '*.js'.
Related Tools
Handwriting Generator
Convert typed text into an image with handwriting appearance. Useful for adding a personal touch to digital work.
Resume Generator
Fill a simple printable A4 CV from a form with personal data, education and experience.
Favicon Generator
Generate a favicon from text/emoji in all common sizes (16, 32, 48, 64, 192, 512). PNG download.