It not only helps locate files in the file system, it also allows you to manipulate what it finds.
Keep in mind
Not all find implementations are created equal. This post is best on the GNU implementation.
The basics
The find command has the following structure:
Where DIR
is the directory in which you wish to search, OPTS
are search options, and EXP
is an expression by which to search.
The most basic practical use might look something like this:
Which translates to âfind anything named exactly config
within cwd
(.
) and its contained directoriesâ.
This would print the paths (relative to where find is launched) for all files and directories that match the given pattern.
So for a file named config
in a directory named config
, it would output:
The options
For clarity, Iâve grouped them under three categories: Filters, Operators and Actions.
This separation should make them easier to reason about.
Filters
Technically called tests
, these will tell find what âsort of thingsâ you are after.
-type
Tells find to only consider certain type of files:
-name / -path
When asking for the name, find will look for a match with the last portion of the path, so after the last /
.
When asking for the path, it will look for any path that exactly match the given string.
So if you want to find all files within a something
directory, but there are many such directories under cwd
, you would tell find to look for files with something
as a part of their paths:
As you can see, the EXP
part of the command takes a reduced regex (which is why it only matches the exact string by default).
Here, we include the wild-card *
, which will match for cwd/path/something/myFile
and/or cwd/something/myOtherFile
.
Both the -name
and the -path
filters have case-insensitive versions: -iname
and -ipath
.
-regex
Unlock the full potential of regex by using the -regex
flag!
-mindepth / -maxdepth
Unless told otherwise, find will always search recursively throughout the directory structure. You can limit the scope of the command by setting its -mindepth
and -maxdepth
.
These filters take a number as parameter: 1
is the directory passed to find (cwd
as .
in our examples so far), 2
is its direct children directories, and so on.
So find . -maxdepth 1 -type f -name 'whoami'
would look for a file named whoami
only within the starting directory (ignoring its child directories).
While find . -mindepth 2 -type f -name 'whoami'
would look for that same file in all directories under cwd
, excluding cwd
itself.
Operators
Mix, match or negate multiple searches:
So find . -name 'hi' -o -name 'mom'
would look for files named hi
or mom
.
Actions
There are a bunch of actions find can perform. By far the most common and useful one is -exec
.
-exec / -execdir
You might need to further manipulate the output of a find command. Usually however, youâll find that the tools you want to use donât read from stdin
but rather expect the input as params.
You could use xargs
for this, but the find command offers a built-in alternative.
You can use -execdir [COMMAND] "{}" \;
(or -exec
) at the end of your command to achieve âpipe likeâ functionality.
Here, the [COMMAND]
is rm
, the "{}"
is whatever find found (quoted to avoid shell expansions), and \;
indicates the end of the -execdir
command.
This example means âremove all files named âremoveMeâ from cwd
and its subdirectoriesâ.
There are a couple of things to keep in mind here:
exec vs execdir
Although most of the examples youâll see around use -exec
, this launches the [COMMAND]
from wherever you ran find from.
Instead, use -execdir
to run the command from the directory used as findâs search parameters.
exec vs shell
When we say that âexec runs a given commandâ, what we really mean is that find runs the exec
application with the given parameters. exec
doesnât really know about shell specific functions, aliases or piping or redirecting outputs.
This is why youâll commonly see something like -exec bash -c "your_cool_cmd 'params' {}"\;
. This way, you can make full use of all of, in this case, bash
âs niceties.
\;
vs \+
You might find some examples ending with a \+
instead of the \;
shown above.
Simply put: \;
tells -exec
to run its command once per result, while using \+
the command will run only one time taking all results from find as a single parameter.
So \+
is more efficient but, depending on the use case, not always a good fit.
Read more about it here.
Common use cases
Remove empty directories
Detailed results
Find all config
files and print their properties as such:
Path globs
Say you want the config
files under the dotfiles/
directory but you donât know in which subdirectory they are.
Will output the config
files somewhere within the dotfiles/
directory.
Exclude specific path
Find all files ending in .py
, while discarding the ones under site-packages/
.
Print only the path to a file
Prints the relative path (from cwd
) to the results excluding their name.
Count stuff
Will count how many lines are in each file under the UserLogin
module, and print out a total as a bonus!
Fancy things you can do
Clean up
You are done âlegallyâ downloading music and want to clean up the left behind crap from your Music/
directory:
You could be more concise with a well put-together regex, the point is that you can achieve this sort of things without it.
More Execdir
Result-dependent sed
Replace all occurrences of dance
for Just Dance
in any file named exactly gaga
within the lady
directory.
Learn more about sed.
Remove trailing spaces from directories
Yep.
Redirect output
Here we create a new file for each match processed by find.
Pipe output
Translates to: âList all directories not containing a file called list
or download
only directly under cwd
â.