find without tears

· Small Sharp Tools


find has a reputation for being unmemorable. It is not: there are four
shapes, and everything else is a variation on one of them.

Files by name, under one directory

$ find lib -name '*.rb'
lib/pulpmesh.rb
lib/pulpmesh/post.rb
lib/pulpmesh/site.rb

Quote the pattern. Unquoted, the shell expands *.rb against the current
directory first and find receives whatever that happened to match.

Files newer than a reference

$ touch -d '2026-01-01' /tmp/cutoff
$ find src -type f -newer /tmp/cutoff
src/parser.c
src/parser.h

There is no -newerthan '2026-01-01'. A reference file is the interface.

Prune a subtree

$ find . -name node_modules -prune -o -name '*.json' -print
./package.json
./config/tsconfig.json

The -o is doing real work. Without -print on the right side, the default
print applies to both branches and the prune is decorative.

Hand the results to something else

$ find . -name '*.log' -print0 | xargs -0 wc -l
   1204 ./build.log
    318 ./serve.log
   1522 total

-print0 and -xargs -0 travel together. Any pipeline that omits them is one
filename with a space away from doing something surprising.

What I still look up

Every single time: -mindepth, -maxdepth, and which order they have to
appear in relative to the tests. The answer is that they are options, not
tests, so put them first.

shell find
last updated: