find walks directory trees and finds things: files by name, by size, by age, by type — then acts on what it found. Where grep searches inside files, find is the tool for "where is the file itself?".

By name #

Find files by name, case-insensitively
$ find . -name "*.log"
$ find /var -iname "*aospix*"

The search path comes first (. means here), the tests after. Quotes around patterns stop the shell from expanding them before find sees them.

By size, age, and type #

TestMatches
-type f / -type dFiles / directories
-size +100MLarger than 100 megabytes
-mtime +30Modified more than 30 days ago
-mmin -5Modified in the last 5 minutes
-maxdepth 2Do not descend deeper than 2 levels
The large files under /var, with sizes
$ find /var -type f -size +100M -exec ls -lh {} \;

Act on results #

-exec runs a command on every match, with {} standing for the path:

Find and clean up in one pass
$ find . -type f -name "*.tmp" -delete
$ find . -type f -name "*.sh" -exec chmod +x {} \;

-delete is preferred over an exec into rm — it acts only on paths the tests matched, exactly as found.

Combine tests #

Tests are ANDed by default; -o is OR, ! negates:

Config files, excluding anything in node_modules
$ find . -type f \( -name "*.yml" -o -name "*.yaml" \) ! -path "*/node_modules/*"

find pairs naturally with chmod for permission sweeps and with rm for cleanups. More of the terminal notes series is on the journal.