find Cheatsheet - Linux File Search Reference
locate answers from a prebuilt index and is fast but stale; find computes on every run and is slower but authoritative, and it is the only one that can filter by size, age or permission bits and then act on what it finds. The sheet spans six filter dimensions plus an actions group: -iname for case-insensitive matching, -type to separate directories from files and symlinks, -size +100M, -mtime -1, permission bitmasks, and ownership cleanup. The actions group is what find cannot be replaced for: -exec feeds matches one at a time, -exec ... + batches them to amortise process startup, and -delete removes them directly. The judgement calls matter more than the flags: find follows symlinks by default and imposes no depth limit, so on a large tree it needs -maxdepth and -prune to finish in reasonable time. Boolean ordering is the other trap, since expressions like -prune -o -print rely on short-circuit evaluation and print the wrong set when reordered. Run a plain -print pass before adding -delete; it is the only insurance that operation has.
Typical Use Case
When a live disk alert climbs to 90 percent but you are not sure which directory is growing, that is the most common use case for find. Start with du for the directory overview, then list files over 1G directly with find . -type f -size +1G, and use -mtime -3 to find files touched in the last three days — often an abnormal log or temp file. Once you find the culprit, pair -exec or -delete to clear stale .log/.tmp files in one pass, far more efficient than browsing directories on a full disk.
By Name 6
find . -name "file.txt"find . -iname "file.txt"find . -name "*.log"find . -name "file*"find /var/log -name "*.gz"find . -maxdepth 2 -name "*.log"By Type 5
find . -type ffind . -type dfind . -type lfind . -type f -name "*.sh"find . ! -type dBy Size 5
find . -size +100Mfind . -size -1kfind . -emptyfind . -size 0find . -size +10M -size -100MBy Time 5
find . -mtime -7find . -mtime +30find . -mmin -60find . -atime -1find . -newer file.txtBy Permission 4
find . -perm 755find . -perm -u+xfind . -perm /o+wfind . -perm -g=wBy Owner 5
find . -user tomfind . -group devfind . -uid 1000find . -nouserfind . -nogroupActions 7
find . -name "*.tmp" -deletefind . -name \"*.sh\" -exec chmod +x {} \;find . -name \"*.log\" -exec rm {} +find . -name "*.txt" -printfind . -name \"*.bak\" -ok rm {} \;find . -name node_modules -prune -o -name "*.js" -printfind . -type f -exec ls -lh {} + | sort -k5 -rhParameter matrix
| Parameter | Effect | Example |
|---|---|---|
-name <pattern> | Match on file name with shell wildcards; case sensitive | find . -name "*.log" |
-iname <pattern> | Same as -name but case insensitive, for directories holding mixed-case extensions | find . -iname "file.txt" |
-maxdepth N / -mindepth N | Bound the recursion depth so a large tree is not walked end to end for nothing | find . -maxdepth 2 -name "*.log" |
-type f|d|l | Filter by node type - regular file, directory, symlink - the precondition for any later action | find . -type f |
! -type d | Negate to drop directories and emit everything else, symlinks included | find . ! -type d |
-size +100M / -size -1k | Filter by size, plus for larger than and minus for smaller than, to pin down what fills the disk | find . -size +100M |
-size +10M -size -100M | Stack two -size tests into a range, keeping only files between the two thresholds | find . -size +10M -size -100M |
-empty / -size 0 | Hit empty files and directories, or restrict the check to zero-byte files | find . -empty |
-mtime -N / -mtime +N | Select a modification-time window: minus means within the last N days, plus means older than N days | find . -mtime -7 |
-mmin -N | Drop the time granularity to minutes, for logs and configs that just changed | find . -mmin -60 |
-newer <reference> | Use one file modification time as the baseline and return everything newer | find . -newer file.txt |
-perm 755 / -perm -u+x / -perm /o+w | Three permission forms - exact match, contains a bit, any-of - with clearly different meanings | find . -perm /o+w |
-user / -group / -uid | Filter by ownership, to clean up output produced by one account or group | find . -user tom |
-nouser / -nogroup | Hit entries with no owner or no group, the signature of leftovers from deleted accounts | find . -nouser |
-delete | Delete matches directly with no external command attached; it really changes the filesystem | find . -name "*.tmp" -delete |
-exec <cmd> {} \; | Start one command per match, which copes with paths containing spaces and newlines | find . -name "*.sh" -exec chmod +x {} \; |
-exec <cmd> {} + | Batch every match into a single invocation, far cheaper in process overhead | find . -name "*.log" -exec rm {} + |
-ok <cmd> {} \; | Ask for confirmation per match, the only built-in guard before a bulk action | find . -name "*.bak" -ok rm {} \; |
-prune | Prune an entire subtree such as node_modules and keep matching the rest | find . -name node_modules -prune -o -name "*.js" -print |
-print | Print matches only as a read-only dry run, then swap in the delete action once verified | find . -name "*.txt" -print |
Common pitfalls
SymptomAfter the delete some files are still there, or directory contents that should have been kept got wiped.
Cause-exec and -delete modify the filesystem during the walk, so an over-broad pattern removes files with no way back.
FixSwap the action out first, run a read-only combination such as find . -name "*.txt" -print to list the hits, check them one by one, then put -delete back.
SymptomOn a large tree the command prints nothing for a long time and looks hung.
Causefind recurses from the start point to every leaf and reads each directory on the way down, which gets expensive purely by directory count; nothing is wrong with the disk.
FixShrink the scope with find . -maxdepth 2 -name "*.log", prune directories you do not need, then widen the conditions gradually.
SymptomThe same file appears in one run and is missing from the next.
CauseThe tree keeps changing while find walks it - an application writing logs, a build writing artifacts - so find is reading a directory tree in motion.
FixNarrow the scope to a concrete directory with find . -maxdepth 2 -name "*.log", or wait for writes to stop; do not take a full count during a heavy write period.
SymptomRunning -exec one match at a time on a big tree takes minutes.
CauseThe per-match form starts a process for every hit, so with tens of thousands of matches the spawn and scheduling cost dwarfs the work the command actually does.
FixUse the batch form find . -name "*.log" -exec rm {} + to hand every path to a single invocation.
SymptomThe target clearly exists, yet find reports no such file or directory.
CauseWhen a pattern contains spaces or wildcards and is left unquoted, the shell expands it first into names in the current directory, so find never receives the original pattern.
FixQuote the pattern, as in find . -name "*.log", and make sure the relative form matches the walk start point.
SymptomAfter cleaning up with -empty the directory structure collapsed and the toolchain stopped starting.
Cause-empty matches empty files and empty directories alike, so removing empty build directories breaks anything that relies on that layout.
FixRestrict the sweep to regular files, for example find . -type f -empty -delete, which touches files only.
SymptomThe goal was to exclude node_modules and the whole result set came back empty.
CauseWhen -prune evaluates true it drops the whole branch; if it is not separated with -o it also swallows the matches that should have continued.
FixJoin the two sides with -o as in find . -name node_modules -prune -o -name "*.js" -print and confirm no grouping was rewritten around them.
SymptomThe permission count is off by an order of magnitude from what was expected.
Cause-perm 755 demands an exact match, so a single setuid bit or a different group field excludes the file, while -perm -u+x and -perm /o+w are contains and any-of tests with a far larger hit set.
FixDecide which relation you mean: exact with find . -perm 755, contains with find . -perm -u+x, or a loose sweep with find . -perm /o+w.
SymptomThe report mixes files and directories and looks like it double-counts.
CauseA search without -type returns directories too, and find . -type f and find . -type d walk the same paths, so merging the outputs without deduplicating repeats rows.
FixState the type explicitly, or keep non-directories only with find . ! -type d, and check for overlap when merging the two lists.
SymptomThe search for recently modified files returns nothing.
CauseThe sign on a time test is easy to invert: -mtime -3 is within the last three days while -mtime +3 is older than three days, so a flipped sign lands the window in an empty range.
FixValidate the direction with find . -mtime -7 first, confirm there is output, then move to an older cut such as -mtime +30.
Troubleshooting
1Narrow the scope first and confirm depth plus filters behave as expected
find . -maxdepth 2 -name "*.log"With -maxdepth the output must stay within two levels; empty means nothing matches at this depth, too much means the filter needs to get stricter.
2Rank by size to find what actually fills the disk
find . -type f -exec ls -lh {} + | sort -k5 -rhThe top lines after the reverse sort are the largest files; if this is slow, bound the walk with -maxdepth first.
3Keep only the files inside one size band
find . -size +10M -size -100MTwo stacked -size tests form the range; an empty result means nothing lives in that band, not that the command is wrong.
4Skip the heavy directory and keep matching the rest
find . -name node_modules -prune -o -name "*.js" -printThe matched node_modules and everything under it stay out of the output while the other .js files remain, which shows the -o join is correct.
5Sweep for world-writable files as a security check
find . -perm /o+wAny output means a file is writable by others; review each one to confirm it is a deliberately shared directory such as a cache.
6Hunt leftovers whose owning account no longer exists
find . -nouserThe listed paths have no matching user, meaning the owner is gone from the system; reassign ownership or clean them up.
7Check permission bits with the symbolic form instead of an exact number
find . -perm -u+xThis hits every file the user can execute; if the count looks far off, compare against find . -perm 755 for the exact-755 subset.
Command Examples
List files larger than 1GB below the current directory
find . -type f -size +1G-size +1G matches regular files larger than 1G. Drop -type f and large directories join the list as well, which is rarely what you want.
Output
./backup/dump.sql ./media/concert_4k.mp4
Find config files modified in the last 3 days
find /etc -type f -mtime -3-mtime -3 covers anything modified within the last three days, =3 means exactly three days ago and +3 means older than three days. The sign decides the direction, and getting it backwards is the classic slip.
Output
/etc/nginx/nginx.conf /etc/hosts
Delete log files older than 30 days
find /var/log -name "*.log" -mtime +30 -delete-delete really deletes and prints nothing. Run the same search without it to confirm the scope, then either add -exec rm {} \; or go ahead and enable the flag.
Common Pitfalls
- find recurses the whole tree by default and can be slow on big directories; limit depth with -maxdepth or prune skipped dirs with -prune.
- The -mtime N semantics vary: -3 is within the last 3 days, 3 is exactly 3 days ago, +3 is more than 3 days ago — mixing them up selects the wrong range.
- -exec and -delete really change files; list matches without them first, then enable deletion or actions after confirming.
- Symlinks are not followed by default; use -L or -follow if you need to, otherwise targets can be missed.
- find matching differs from shell glob; quote patterns with single quotes so they are not expanded early when matching names with spaces.
Tips
- find searches the current directory recursively by default; use -maxdepth 1 to limit it to the current directory only.
- In -exec, {} stands for the found file; \; runs the command per file, while + batches them.
- Preview with -print before deleting, to confirm matches and avoid accidental deletion.
FAQ
How do I choose between find -exec and xargs?
For small result sets and simple commands, run them inside find with -exec {} + or -exec {} \;. For large sets or complex per-item handling, pipe to xargs — be sure to combine -print0 on the find side with -0 on the xargs side, otherwise filenames containing spaces or newlines break the command.
How do I safely delete the files that find matches?
The safest way is adding -delete to the find command, which removes the matched files in place without going through an alias. If you need a pipeline, prefer find ... -print0 | xargs -0 rm. Avoid bare xargs rm or wrapping find in command substitution, which mishandles or fails on unusual filenames.
How do I find several file types (such as txt and log) at once with find?
Wrap the individual -name rules with the -o operator inside a pair of parentheses and pair that with the implicit -a, for example placing the -name for txt and the -name for log inside one parenthesized group followed by -type f. Without the parentheses, -o mixes with -a in a precedence that rarely matches what you intend.
Why does find -name differ from matching the full path?
-name matches only the base filename and ignores the directory part, whereas -path matches the full path. When filtering on multi-level paths or excluding directories, use -path together with -prune, and limit the scope with -maxdepth to avoid scanning the entire filesystem.
What do the sign and number mean for find -mtime and -mmin when filtering by modification time?
-mtime N selects files modified within the 24-hour window N days ago, -mtime -N means within the last N days, and -mtime +N means older than N days. For minute precision use -mmin, for example -mmin -30 selects files modified in the last 30 minutes. Note -mtime rounds to whole days, so boundary values are easy to misread.
Official References
Each command links to its official documentation below, so you can verify the latest usage and read deeper.
Maintained by LaoHand
Publicly updated on Jul 21, 2026, continuously proofread against official docs.
Contact Us
Wrong command or description? Send us corrections, business inquiries or product feedback by email.
Contact Us