Using the Find Command

There’s a very powerful command that can save you lots of headaches when used in the right places; it’s called find. It walks through the file tree, starting from the provided path. Next, it prints each directory and file including its path relative to the current working directory.

Just try it, enter the following and see what output you get:

$ find .

For me, the output looks like:

.
./images
./images/cover.jpg
./scripts
./scripts/loop.sh
./scripts/arguments.sh
./scripts/words.txt

The first dot is simply the current directory. Find will both output directies and files. If you only want to list files, use:

$ find . -type f

If you only want to list directories, use:

find . -type d

Expressions

These are just the basics. Find also takes expressions, which further narrows down what files it should return. A useful expression that I use often is -mtime. The following command returns all files that were modified more than 5 minutes ago:

$ find . -type f -mtime +5m

The m is a modifier, all available modifier are listen in the following table:

Modifier Meaning
s second
m minute (60 seconds)
h hour (60 minutes)
d day (24 hours)
w week (7 days)

The plus sign is important as well:

  • a preceding plus sign means "more than n"
  • a preceding minus sign means "less than n"
  • neither means "exactly n"

Another useful expression is -name, which will filter the results based on the file name. For the name, you can use a shell pattern. So the command find . -name "*.txt" will only return files with the .txt-extension.

Using the results

With our new ninja scripting powers, we can now use find to return a bunch of files, feed them to our for loop and do some awesome stuff with them, right?

True, but since it’s pretty obvious you want to perform some actions on the returned files, find has us covered already. No scripting necessary.

Say you want to delete the files that match your criteria, you can simply add -delete to your find-command. This is obviously a bit dangerous, so before using this flag, always check the output of the find-command without it first.

What gives us much more flexibility, is the -exec flag. It allows us to execute any command. An example that you may have seen before is this one:

$ find /path/to/files* -mtime +5m -exec rm {} +

Let’s break it down:

  • find all files in the given path that are modified more than 5 minutes ago
  • execute the rm command (which deletes the files)
  • {} + is replaced with as many pathnames as possible for each invocation of the given utility (in our case ls)

This is actually a very efficient way of removing lots of files, like thousands or even millions.

A slight alternative to this command is:

$ find /path/to/files* -mtime +5m -exec rm {} \;

The difference is that rm is now executed for every single file, instead of as many files per batch as your system allows. Which version you use depends on the command you’re executing on the results. If you can use the one with the plus sign, it’s a lot faster! That’s because the command is executed on many files at once, saving your OS lots of CPU cycles that are needed to open, start, run, and exit a program. However, some commands take just one file at a time and for those, the second version comes to rescue.

And again: if you enter man find, you’ll get the full documentation. But I’ll admit; I tend to google this stuff too because you generally get useful examples instead of needing to plow through the raw documentation. However, always try to understand exactly what it is you’re pasting into your terminal before hitting enter!


If you liked this page, please share it with a fellow learner: