Finding files: find, locate & which
Search by name, type, size, time and owner, act on results with -exec, and find commands on your PATH.
"Where did I put that config file?" "Which logs are eating my disk?" "Delete every .tmp file older than a week." The find command answers questions like these by walking a directory tree and testing every file against rules you give it. We'll also cover quicker tools for finding commands.
Practice tree (create it once):
(A \ at the end of a line continues the command on the next line.)
The shape of a find command#
- WHERE: one or more starting directories (
.is here,/is everything,~is home). - TESTS: conditions like name, type, size and age. Several tests are ANDed together.
- ACTION: what to do with matches. The default is
-print(print the path).
find lists files in on-disk order, which may differ on your machine. Pipe to sort if you need a stable order.
Finding by name#
Always quote the pattern. Unquoted, the shell would expand *.md in the current directory first (to README.md), and find would only search for that one name.
Search the whole system for a file, hiding "Permission denied" noise:
Finding by type#
Finding by size and age#
A classic disk-space hunt:
-xdev stays on one filesystem, so find doesn't wander into network mounts or /proc.
Combining and excluding#
Tests are ANDed. Use -o for OR, ! (or -not) for NOT, and escaped parentheses for grouping:
For big folders you don't want to descend into at all, -prune is faster than filtering afterwards:
Read it as: "if the path is ./node_modules, prune it (don't go in); otherwise print .md files". The explicit -print at the end is required here.
Acting on what you find#
-exec
{} is replaced by each path, and \; ends the command (escaped so the shell doesn't eat the ;). Ending with + instead of \; passes many paths to one command, which is much faster:
-delete
Always run the command with
-deletelast:find . -delete -name "*.tmp"deletes everything, because actions run in order.
Piping to xargs safely
File names can contain spaces (and even newlines). -print0 separates names with a NUL byte, which xargs -0 understands:
Without -print0/-0, release notes.md would be split into two bogus names.
locate: instant searches from an index#
find walks the disk live, which can be slow. locate searches a prebuilt database instead:
The trade-off: files created since the last updatedb won't show up.
Finding commands: which, type, whereis#
When you type a command name, the shell searches the directories listed in the PATH variable, in order. To see which file wins:
whichprints the first match onPATH.type(a Bash built-in) also reveals aliases, functions and built-ins, so it's the most truthful answer.whereislists the binary (-b), and without options also source and man pages.command -v gitis the portable way for scripts to check whether a tool is installed: it prints the path, or nothing with a non-zero exit status.
Common mistakes#
- Unquoted patterns:
find . -name *.txt. - Forgetting the starting directory on older systems (
find -name xworks in GNU find but not everywhere). - Using
-deletewithout previewing, or placing it before the tests. - Misreading sizes:
-size -1kmeans "rounded up to 1 KiB blocks, fewer than 1", i.e. empty files only. Usec(bytes) for precision:-size -1000c. - Parsing
lsoutput in scripts instead of usingfind ... -print0.
What's next#
find locates files by their properties. To search inside files for text and patterns, you need grep and regular expressions.
Check your understanding
Quick quiz
1.Which command finds all regular files ending in
.logunder/var/logthat are larger than 100 MB?2.Why should you quote the pattern in
find . -name "*.txt"?3.You type
python3and want to know exactly which file on disk runs. Which command tells you?
Finished reading?
Mark this lesson complete to track your progress.