Terminal · intermediate

Finding files with find

find walks the directory trees rooted at its starting points and evaluates an expression for every encountered pathname. The expression combines options, tests such as -type or -name, actions such as -print or -exec, and operators that control which parts run.

Why it matters

find can search by metadata and pass matching pathnames directly to other programs without parsing formatted directory listings. That makes it safe for unusual filenames, but only when shell quoting, expression precedence, and destructive actions are handled deliberately.

Mental model

How to reason about finding files with find

Read find as find STARTING_POINT... EXPRESSION. For each pathname, it evaluates the expression left to right with ! before implicit -a and -a before -o, short-circuiting when the result is known. If no output-affecting action is present, a matching expression gets an implicit -print.

Analogy

An inspector walks every aisle from each chosen entrance. For every item, the inspector evaluates a boolean checklist in precedence order; actions such as printing a label or handing the item to another worker run only when evaluation reaches them.

Examples

See the boundary, not just the happy path

Worked example · Find recent log files

find /var/log -type f -name '*.log' -mtime -7 -print

The shell quotes the pattern so find receives it literally. find then selects regular files whose names match and whose modification time falls within its last seven 24-hour buckets.

Worked example · Group alternative names

find . -type f \( -name '*.jpg' -o -name '*.png' \) -print

Escaped parentheses make the name tests one grouped condition, so -type f applies to both alternatives. The quoted globs reach find instead of being expanded by the shell.

Worked example · Find large regular files

find . -type f -size +100M -print

Adjacent tests have an implicit -a, so a pathname must be both a regular file and larger than 100 mebibytes in GNU find's M unit before it is printed.

Worked example · Batch a safe action

find src -type f -name '*.dart' -exec grep -lF TODO {} +

-exec ... {} + passes matched pathnames directly as arguments in batches. It preserves whitespace and newlines in names and usually launches fewer processes than the \; form.

Avoid · Parsing ls output

for file in $(ls *.log); do process "$file"; done

Command substitution and word splitting lose filename boundaries; find actions or shell globs preserve pathnames as arguments.

Common mistakes

Misconceptions to remove early

Leaving -name patterns unquoted

The shell can expand *.log before find starts, changing one intended pattern into unrelated command arguments.

Leaving -o alternatives ungrouped

Because -a binds more tightly than -o and evaluation short-circuits, find . -type f -name '*.c' -o -name '*.h' -print does not apply -type f or -print to both branches. Escape parentheses around the alternatives.

Treating -mtime as calendar dates

-mtime works with rounded 24-hour periods rather than calendar-day labels. Use -mmin for minute-scale age, -newermt in GNU find for date parsing, or explicit reference files when exact boundaries matter.

Adding -delete before validating selection

Print and review the same expression first, narrow its starting point, and understand that -delete is non-POSIX, irreversible, and implies depth-first traversal in GNU find.

Quick check

Can you predict the result?

1. Why should '*.json' be quoted in find . -name '*.json'?
  • So find receives the pattern instead of the shell expanding it in the current directory.
  • So JSON files become hidden.
  • Because -name accepts only quoted strings.
Answer: So find receives the pattern instead of the shell expanding it in the current directory.
2. What advantage does -exec command {} + have over parsing printed pathnames?
Answer: It passes pathnames directly as arguments in batches, preserving names that contain whitespace or newlines.
3. How should you make -type f apply to both '*.jpg' and '*.png' alternatives?
Answer: Group the alternatives with shell-protected parentheses: find . -type f \( -name '*.jpg' -o -name '*.png' \) -print.
4. What is the practical difference between -exec command {} \; and -exec command {} +?
Answer: The \; form runs one command per match, while the + form batches multiple matched pathnames into each command invocation.

Keep building

Put the concept to work

Practical guides that use this mental model

Authoritative references

Make the idea retrievable.

Concepts are coming to Terminaster in the next update. You'll be able to study this one with spaced repetition, next to the commands where you use it.

Get Terminaster