10 KiB
find — quick reference & practical documentation
This is a compact, practical reference for the Unix/Linux find command aimed at DevOps engineers and system administrators. It covers common options, tests, actions, operators, examples (safe and practical) and performance tips.
Synopsis
find [path...] [expression]
If no path is given, find searches the current directory (.). expression is evaluated left-to-right and can contain tests, actions and operators.
Basic behaviour
findwalks directory trees recursively by default.- An expression evaluates to true/false; when true, the default action
-print(or whatever action is specified) is executed. - You can control traversal order with
-depthand-maxdepth/-mindepth. -pruneprevents descending into directories.
Common options and switches
-H: follow symbolic links specified on the command line.-L: follow all symbolic links.-P: never follow symbolic links (default).-xdev: don't descend into directories on other filesystems (useful when walking/).-mindepth N: do not apply tests/actions to files at depth < N.-maxdepth N: do not descend past depth N.-depth: process directory contents before the directory itself (useful for safe deletes).-mount: same as-xdev(GNU find).
Common tests (predicates)
-
-name pattern: match basename with shell globbing (case-sensitive). Pattern uses shell wildcards (*,?,[]). -
-iname pattern: case-insensitive-name. -
-path pattern: match the whole path (slash-separated) with shell globbing. -
-ipath pattern: case-insensitive-path. -
-regex pattern: match full path with regular expression (syntax differs byfindimplementation; GNUfinddefaults to Emacs regex). -
-type c: file type;f= regular file,d= directory,l= symlink,c= character device,b= block device,p= FIFO,s= socket. -
-perm mode: file permission test. Modes:- octal:
-perm 0644(exact) - symbolic:
-perm -u=w(any of the bits),-perm /u=w(any),-perm -0644(all bits set) - GNU
findalso accepts/modeto mean "any of the bits".
- octal:
-
-user name/-uid uid: owner. -
-group name/-gid gid: group. -
-size n[cwbk]: file size; default 512-byte blocks for somefindversions; most use 1K blocks fork. GNUfindsuffixes:c= bytesk= kilobytesM= megabytesG= gigabytes+n= greater than n,-n= less than n,n= exactly n
-
-mtime n/-atime n/-ctime n: modified / accessed / changed time in 24-hour periods;-mtime +7older than 7 days,-mtime -7less than 7 days,-mtime 7exactly 7. -
-mmin n,-amin n,-cmin n: minutes. -
-newer file: newer than file (can be combined with!to negate). -
-empty: empty file or directory. -
-links n: number of hard links. -
-readable/-writable/-executable: access checks from running user perspective.
Common actions
-print: print path (often default; some implementations require explicit-printwith complex expressions).-print0: print paths separated by NUL (safe with whitespace/newlines).-ls: list file usingls -dilsstyle.-exec command {} \;: runcommandonce per matched file.{}is replaced by the current path. The\;terminator must be escaped or quoted.-exec command {} +: optimized form; appends multiple matches to command arguments likexargs(more efficient).-ok command {} \;: like-execbut prompts the user before each execution.-delete: delete matched files/directories (be careful; obeys ordering and-depth).-prune: exclude directory from descent (returns true; often used with-o).-quit: stop after first match (very efficient when used with-print).-mindepth N,-maxdepth Nalready described; they behave like tests.
Operator precedence (GNU find style)
-
Parentheses
()group expressions. They must be escaped or quoted:\( ... \)or'(' ... ')'. -
!or-not: logical NOT (unary). -
-aor implicit concatenation : logical AND. -
-oor-or: logical OR. -
Evaluation is left-to-right;
-ahas higher precedence than-o. Use parentheses to be explicit. -
Common pitfall: mixing
-pruneand-orequires careful grouping: Example pattern to excludedir:find . -path ./dir -prune -o -printThis means: if path is
./dirprune it (and-prunereturns true) otherwise (-o)-print.
Typical practical examples
Search examples assume bash shell; escape parentheses and semicolons as needed.
- Find files by name (case-sensitive)
find /var/log -type f -name "syslog*"
- Case-insensitive:
find /home -type f -iname "*.jpg"
- Find empty directories:
find /path -type d -empty
- Delete
*.tmpfiles safely (print first, then delete)
find /data -type f -name "*.tmp" -print
find /data -type f -name "*.tmp" -delete
Or safer with confirmation:
find /data -type f -name "*.tmp" -ok rm {} \;
- Find and remove files older than 30 days (safe: use
-printfirst)
find /var/log -type f -mtime +30 -print
find /var/log -type f -mtime +30 -exec rm -- {} +
Prefer -exec ... + over -exec ... \; for efficiency.
- Remove directories older than 30 days (use
-depthto ensure files inside are removed first)
find /tmp -depth -type d -mtime +30 -exec rm -rf -- {} +
-delete may also be used but beware of ordering; -depth ensures children processed before parent.
- Find files with spaces and handle them safely:
find /srv -type f -name "*.conf" -print0 | xargs -0 grep -H "pattern"
- Find files larger than 100 MiB:
find / -type f -size +100M -print
- Find files newer than a reference file:
find /web -type f -newer /tmp/deploy_marker -print
- Find and run a command on many files (batching):
find /data -type f -name "*.log" -exec gzip -- {} +
- Exclude a directory (
dir_to_skip) while listing everything else:
find . -path "./dir_to_skip" -prune -o -print
- Only search one level (non-recursive):
find . -maxdepth 1 -type f -print
- Find broken symlinks:
find / -xtype l -print
Note: -xtype tests the target type; -L changes behavior of -type.
- Use
-printfto customize output (GNU find):
find . -type f -printf "%p\t%k KB\t%TY-%Tm-%Td %TH:%TM:%TS\n"
-printf supports format sequences (%p path, %s bytes, %k KB blocks, %TY year, ...). Exact spec depends on implementation (GNU has extensive options).
- Stop at first match (fast):
find /usr -type f -name "passwd" -print -quit
- Find files modified within last 15 minutes:
find /var -type f -mmin -15
Safe deletion checklist
- Always
-printor-lsfirst to verify matches. - Prefer
-exec rm -- {} +or use-deletewith-depthif required. - Watch out for
-maxdepth/-mindepthto avoid accidental top-level deletions. - Use
-print0+xargs -0when passing to other utilities. - Consider using
-okfor destructive changes in interactive contexts.
Performance & scalability tips
- Limit scope: pass explicit starting paths instead of
.or/when possible. - Use
-maxdepthand-mindepthto reduce traversal. - Use
-xdevto avoid crossing filesystem boundaries (speeds up root scans). - Combine fast tests early (e.g.,
-type f -name "*.log"rather than-namealone) because find evaluates left-to-right; short-circuiting happens when possible. - Prefer
-exec ... +to-exec ... \;to reduce process spawn overhead. - Use
-pruneto skip large tree branches that aren’t needed. - On very large trees consider tools optimized for indexing (e.g.,
locate/mlocate,fd, or ripgrep for content search).findis always consistent but traverses the disk each run.
Portability notes
- Behavior, available tests/actions and argument formats vary slightly between implementations (GNU
findvs BSDfindvs BusyBox). Examples above assume GNUfindwhen using-printf,-delete,-quitor suffixes likeM/Gfor sizes. - When writing scripts for mixed environments, try to stick to portable tests:
-name,-type,-mtime,-print,-exec ... \;. Check/usr/bin/find --versionorman findon target hosts.
Gotchas & common pitfalls
- Shell globbing vs
findglobbing:-name "*.txt"is matched byfindand must be quoted to prevent shell expansion. -permexact vs any-bit semantics differ across versions; test on target system.-regexmatches the whole path, not just basename; regex dialect differs (use-regextype posix-extendedon GNUfindto set type).-deletewill fail if used before tests that select children (order matters). Use-depthor test ordering appropriately.- Beware of running
findas root with-exec rm -rf {}— very dangerous if expression is wrong. Always verify output. -maxdepth/-mindepthmay not be supported in very oldfindimplementations.
Exit status
0: at least one match and command completed successfully.1: no matches were found (behavior can vary).>1: an error occurred (e.g., permission errors or malformed expression). Note: exact meanings can depend on implementation.
Useful combinations
- Find files and preserve relative paths for tar:
cd /path && find . -type f -name "*.conf" -print0 | tar --null -T - -czf confs.tar.gz
- Find and change ownership or permissions:
find /srv/www -type f -name "*.php" -exec chown www-data:www-data {} +
find /srv/www -type d -exec chmod 755 {} +
- Search content in matched files:
find /app -type f -name "*.py" -print0 | xargs -0 grep -n "TODO"
Related commands/tools
locate/mlocate: fast filename lookup (uses database).fd: simpler, faster user-friendly alternative tofind(not always installed).xargs: pass batches of arguments to commands (careful with spaces; use-print0+xargs -0).stat: detailed file metadata for a single file.rm,tar,gzip,chown,chmod,rsync: commonly used alongsidefind.
Quick cheatsheet (most-used patterns)
- Find files by name:
find /path -type f -name "pattern" - Case-insensitive:
-iname - Size bigger than 100M:
-size +100M - Modified > 7 days:
-mtime +7 - Delete old files:
find /dir -type f -mtime +30 -exec rm -- {} + - Print NUL-separated:
-print0 - Safe prune:
find . -path ./skip -prune -o -print - Batch exec:
-exec cmd {} + - Stop on first:
-print -quit