I learned to respect find after aiming a cleanup command one directory higher than intended. Nothing catastrophic happened—the preview caught it—but the wall of unexpected paths made the lesson permanent: the starting point is part of the query, and printing matches is a separate phase from changing them.
A compact syntax reference
-name PATTERNmatches a case-sensitive basename;-inameignores case.-type f,-type d, and-type lselect regular files, directories, and symbolic links.-size +100Mselects sizes greater than 100 rounded MiB units;-100Mmeans less and100Mmeans exactly that rounded unit count.-printemits matching paths; GNU-printfcan emit path, size, time, and other fields.-exec command {} +batches matching paths as arguments instead of launching once per path.-deleteremoves matches and must come after carefully tested selection predicates.
Find a file by name
find ./project -type f -name 'helloworld.pdf'
find ./project -type f -iname '*.pdf'What controls the match
./projectis the traversal root; choosing it narrowly reduces time, permission errors, and accidental matches.-type fexcludes directories, links, sockets, and device nodes.-nameand-inamecompare the basename rather than the full path.Quotes keep
*.pdfintact sofind, not the current shell directory, evaluates the wildcard.
Filter by filesystem object type
find ./project -type f -print
find ./project -type d -print
find ./project -type l -printWhat type means around symbolic links
-typeexamines the filesystem object selected under the current link-following mode.GNU
finddoes not follow symbolic links by default (-Pbehavior).-Lfollows links and changes traversal and type tests; do not add it casually around cyclic or untrusted trees.-xtypeis available when you specifically need the complementary link-target behavior.
Find large files and understand the unit
find ./project -type f -size +100M -print
find ./project -type f -size +104857600c -printWhy these two queries can differ
Mmeans 1,048,576-byte units in GNU find, whilecmeans bytes.+nmeans greater thannunits after the file size is rounded up to that unit.+104857600cis a byte-level test for files larger than 100 MiB.-sizeuses apparent length from filesystem metadata; sparse-file disk consumption can be much smaller.
Print useful evidence instead of bare paths
find ./project -type f -size +10M -printf '%s bytes %p
'
find ./project -type f -size +10M -printf '%s %p\0' | sort -z -n | tr '\0' '
'What makes the output safer
%sprints apparent size in bytes and%pprints the matched path.\0in the displayed command terminates records with NUL, so embedded spaces and newlines do not split filenames inside the pipeline.sort -z -nunderstands NUL-delimited records and compares the leading size numerically.The final
tris display-oriented; unusual names containing newlines can again span visual lines after conversion.
Search only C source files for text
find ./src -type f -name '*.c' -exec grep -Hn -i -- 'main' {} +How find and grep divide the work
findselects regular files whose basename ends in.c.-exec … {} +appends multiple selected paths pergrepinvocation, reducing process overhead.-Hnprints filenames and line numbers;-imakes text matching case-insensitive.--ends grep option parsing so a search string beginning with a hyphen is not treated as a flag.
Combine alternatives without precedence surprises
find ./src -type f ( -name '*.c' -o -name '*.h' ) -printWhy the parentheses matter
Adjacent tests imply logical AND, while
-omeans OR.AND binds more tightly than OR, so grouping makes
-type fapply to both filename alternatives.The backslashes stop the shell from treating parentheses as shell syntax.
Expression evaluation short-circuits from left to right, which also affects which actions run.
Handle permission errors without hiding real failures
find ./project -type f -name '*.log' -print 2>find-errors.log
printf 'find exit status: %s
' "$?"What redirection tells you
2>sends only standard error to the named file; it does not grant access or suppress the exit status.$?must be read immediately afterfindbecause the next command replaces it.A nonzero status means the traversal was not entirely successful even when some paths were printed.
Avoid adding
sudoby reflex; narrow the starting point or correct intended access instead.
Preview first, delete in a separate decision
find ./build-cache -depth -type f -name '*.tmp' -mtime +7 -printWhat must be true before deletion
The starting directory is the intended disposable cache, not
.,/tmp, a home directory, or a variable you have not inspected.-depthvisits children before their directory and mirrors traversal implied by GNU-delete.-mtime +7uses completed 24-hour periods and does not mean “older than exactly 168 hours” in every intuitive boundary case.Read the complete preview, check the exit status, and rerun after any expression change.
find ./build-cache -depth -type f -name '*.tmp' -mtime +7 -deleteRisk level: destructive. Review the command before running it.
Why deletion is deliberately last
-deletepermanently removes each matched file; there is no trash or built-in undo.Placing selection tests before the action makes the intended evaluation order readable.
GNU
-deleteimplies depth-first traversal, which is why the preview explicitly used-depth.Do not combine
-deletecasually with-prune; depth-first behavior makes pruning ineffective.
A dependable mental model
Read a find invocation as a small program: establish the traversal boundary, filter objects, combine conditions with explicit grouping, and finally choose an action. Most dangerous mistakes happen when the boundary is vague, the shell rewrites a pattern, or a destructive action is added before the selection has been observed.
Related Linux storage and package work
Inspect directory sizes interactively with ncdu before searching individual large files.
List files installed by a Linux package when package ownership matters more than path patterns.
Understand disk usage with du when apparent file size and allocated storage differ.
Comments and corrections