find -not, -o, -a: Combine Conditions
find joins predicates with -and, -or, and -not, grouped by escaped parentheses.
Real searches need logic: this name but not that path, files of either extension. Knowing precedence and grouping prevents silent mismatches.
What it does
find combines tests with operators: -a (or -and, the implicit default between predicates), -o (or -or), and ! (or -not) to negate. -a binds tighter than -o, so use escaped parentheses \( \) to group when mixing them. Negation applies to the predicate that follows.
Common usage
find . -type f ! -name '*.min.js'
find . \( -name '*.js' -o -name '*.ts' \) -type f
find . -type f -not -path '*/node_modules/*'Options
| Operator | What it does |
|---|---|
| -a / -and | Logical AND (implicit between predicates) |
| -o / -or | Logical OR (lower precedence than AND) |
| ! / -not | Negate the following predicate |
| \( ... \) | Group expressions to control precedence |
In CI
Because AND binds tighter than OR, find . -name a -o -name b -type f does not mean what it looks like. Wrap the alternation: find . \( -name a -o -name b \) -type f. Combine ! -path with -prune-free patterns to exclude vendored directories.
Common errors in CI
"find: paths must precede expression" often comes from unescaped parentheses the shell interpreted; write \( \) or quote them. "find: invalid expression; you have used a binary operator -o with nothing before it" means an -o sits at the start of a group or after another operator. Forgetting to group -o lets -type f apply to only one branch.