find by name and type
Walking a whole directory tree to locate files by name, ignoring case if needed, and telling files from directories with -type.
What you will learn
- Read `find`'s structure: starting points, tests, actions.
- Search by name with `-name` and `-iname`, quoting the pattern.
- Filter by `-type`, limit depth, and combine tests with `!` and `-o`.
grep searches *inside* files; find searches *for* files. It starts at one or more directories, walks down through every subdirectory, and for each entry it meets it evaluates a list of tests. Entries that pass all the tests get the action, which by default is simply printing the path. The general shape is find [WHERE...] [TESTS] [ACTION], and if you leave out *where*, it starts in the current directory.
~% cd /root/lab/l35
l35% find etc
etc
etc/app.conf
etc/conf.d
etc/conf.d/db.conf
etc/conf.d/net.conf
etc/backup.conf
etc/notes.conf.bak
l35% find etc -name '*.conf'
etc/app.conf
etc/conf.d/db.conf
etc/conf.d/net.conf
etc/backup.conf
l35% find etc -type f -name '*.conf'
etc/app.conf
etc/conf.d/db.conf
etc/conf.d/net.conf
Paths come out relative to where you told find to start: begin at etc and you get etc/..., begin at /root/lab/l35/etc and every line is absolute. The order is the order of the directory on disk, not alphabetical; pipe into sort if you need it sorted.
-name and its quotes
-name PATTERN compares the entry's name (not the whole path) with a wildcard pattern: the same *, ? and [...] from lesson 18, but this time find does the matching. So the pattern must reach find untouched, which means quoting it: find . -name '*.conf'. Without quotes, if the current directory happens to contain app.conf, the shell rewrites the command into find . -name app.conf and you silently get the wrong answer. -iname is the same test ignoring case, so -iname '*.jpg' also finds HOLIDAY.JPG.
-type and friends
| Test | True for |
|---|---|
-type f | regular files |
-type d | directories |
-type l | symbolic links (also b, c, p, s from lesson 19) |
-maxdepth N | do not go more than N levels down (1 = only the start directory's contents) |
-path PATTERN | the whole path matches, e.g. '*/conf.d/*' |
Combining tests
Tests written one after another must all be true: -type f -name '*.conf' is "a file AND named *.conf". -o means OR: -name '*.jpg' -o -name '*.png'. ! negates the next test: ! -name '*.bak'. AND binds tighter than OR, so when you mix them, group with escaped parentheses: find . -type f \( -name '*.jpg' -o -name '*.png' \).
Commands in this lesson
| Command | What it does |
|---|---|
find DIR | List everything under DIR, recursively. |
find DIR -name '*.conf' | Entries whose name matches the pattern. |
find DIR -iname '*.jpg' | The same, ignoring case. |
find DIR -type f | Only regular files (`d` directories, `l` links). |
find DIR -maxdepth 1 | Do not descend into subdirectories. |
find DIR -name A -o -name B | Either test (OR). |
find DIR ! -name '*.bak' | Negate a test. |
Quiz
What is the difference between `grep` and `find`?
- None, they are aliases
- `grep` searches inside files for lines; `find` searches the tree for files
- `find` only works on the current directory
Why should you write `find . -name '*.txt'` with quotes?
- Otherwise the shell may expand `*.txt` before `find` sees it
- `find` requires quotes around every argument
- To make the search case-insensitive
Which command lists only the directories under `/root/lab`?
- `find /root/lab -type d`
- `find /root/lab -name d`
- `find /root/lab -dir`
What does `-iname '*.jpg'` match that `-name '*.jpg'` does not?
- Files inside subdirectories
- `PHOTO.JPG` and other case variants
- Hidden files
`find . -maxdepth 1 -type f` lists…
- The files directly in the current directory, not in subdirectories
- The largest file
- Only the first file found
Practice
Under /root/lab/l35/etc there are configuration files at several depths. Save into /root/lab/l35/confs.txt the paths of all **regular files** whose name ends in `.conf` (one is a directory with a `.conf` name: leave it out).
Several users under /root/lab/l35/home have a **directory** called `cache` somewhere in their tree; one user has a regular file called `cache` instead. Save the paths of the `cache` directories only into /root/lab/l35/caches.txt.
The photos under /root/lab/l35/pics were saved by different cameras, so the extension is `.jpg`, `.JPG` or `.Jpg`. Save the paths of all of them into /root/lab/l35/jpgs.txt with one `find`.
Open this lesson in the app to do the tasks in a real Linux machine and have them checked.