The find command

The find command is a powerful way to operate recursively on a directory hierarchy. This means that you can provide it with a set of directories (or files), and it will apply appropriate tests and actions to them and also to any directories and files within them, such as children and grandchildren.

The default action for find is to print the filenames as it finds them:

$ find ~/recipes
/home/bashuser/recipes
/home/bashuser/recipes/lemon-garlic-fish.txt
/home/bashuser/recipes/japanese
/home/bashuser/recipes/japanese/katsu-curry.txt
/home/bashuser/recipes/gnocchi-and-sauce.doc

You can make this explicit with the -print action:

$ find ~/recipes -print

As long as there aren't too many files in the directory tree at that point, this can be a good way to get a complete file listing of your directory. Because find just prints the files as it finds them, you might want to run the output through sort if you want to read it:

$ find ~/recipes | sort

You can provide multiple directories to a find command; it will iterate through them all. You can also provide filenames directly on the command line. They will still be tested and have the actions run on them:

$ find ~/recipes ~/manuals todo.txt

You can filter the output for find in several ways. One of the most useful is using the -name option:

$ find ~/recipes -name '*fish*' -print

Using -name with this glob-style pattern will print the name of any file or directory that has the fish string in its filename. We could further refine this by adding the -type test, with the f flag to limit the recipes to files:

$ find ~/recipes -name '*fish*' -type f -print

Note that the directories or filenames to search always come first on the command line, and the filters always come before the actions.

To find files based on their modification date, you can use the -mtime test, with a minus (-) or plus (+) prefix for the following number. To find files modified more than three days ago, you could write:

$ find ~/recipes -mtime +3 -print

To find files modified less than five days ago:

$ find ~/recipes -mtime -5 -print

You can negate any of these filters with a single exclamation mark. For example, to find the names of files that do not match the string chicken:

$ find ~/recipes ! -name '*chicken*'
Be careful to make ! a word of its own, with at least one space on both sides, otherwise you might trigger unwanted history expansion.

If there is a subdirectory you wish to ignore somewhere in the tree, you can do this with the -prune action, which stops the descent at that point and continues with the rest of the tree. This can be a useful way of excluding metadata, such as Git or Subversion directories:

$ find myproject -name '.git*' -prune -o -print

In the preceding command line, -o print ("or print") prints the names of found files and directories that are not within a  .git directory.