Skip to content

Find in Linux with examples

Find Linux Cover Photo

Find is a command line utility used to navigate file structures and locate files in the UNIX filesystem, based on certain criteria or conditions. The primary function of the find command is to navigate the directory tree, starting from a defined specified location. The search will begin from the current working directory if no starting directory is provided. Find recursively and systematically explores each directory and subdirectory as it navigates through the directory tree, which means that it will examine every file and directory in its path.

Where find excels is the parametrization of the search, meaning that it applies user-defined criteria to determine the matched files. The parameterization can be expressed using various options provided to the find command, for example – matching the name, type checks, and time-based criteria.

Basic Search

The following forms the basic find syntax:

find [starting-point] [options] [expression]
find /path -name "file.txt"

-name flag specifies a criterion based on the names of the files or directories by searching based on a pattern or matching a filename. We started from /path and we defined the name that we are searching for – file.txt. What about searching based on the type? Well, it is also supported, and we can search for directories (using the flag d), regular files (flag f), and other less-used types (block specials, character specials, pipes, and symbolic links just to name a few).

find /path -type d

We could even combine the -name and -type flags to make our searches even more convenient and specific.

find /path -type d -name "DirectoryName"

What about the scenario in which we know the file name, but are unsure about the case? We can use an alternative pattern flag called -iname. The snippet below would match anything that starts with file, doesn’t matter the case.

find /path -iname "file.*"

What about if the only information about the file is when it was last modified? We also have a flag pattern matching that one named -mtime. With this pattern flag, we check for when the file was last modified based on the argument provided. If we provide a plus sign we find files modified more than n days ago, and a minus sign finds files modified less than n days ago. For files that were modified exactly n days ago we provide no sign.

find /path -mtime [+/-]n

Below we have an example (actually three examples) of using -mtime. In the first one we search for files that were modified more than a day ago, in the second one searching for files modified less than a day ago, and in the third one that were modified exactly a day ago. We can also combine the -mtime pattern with other criteria, such as the -name pattern. Below we are searching for files modified more than 7 days ago that are named file.txt.

find /path -mtime +1
find /path -mtime -1
find /path -mtime 1

find /path -mtime +7 -name "file.txt"

Executing Commands

Additionally, we could take specific actions once we meet the specified criteria, such as printing data, moving, deleting, or editing the files. For example, look at the following snippet:

find /path -type f -name "*.txt" -exec echo {} \;

The first part of the snippet is already well known to us. We have the starting point /path, and based on the options -type f we search for files, and we look for files with the .txt extension.

The -exec command will execute the echo command for each matching file, printing the path. Actually with -exec we can execute any kind of commands. {} is a placeholder representing the current file or directory and \; marks the end of the exec command.

Let us say we want to delete all the files that have a .txt extension AND are greater than 1MB. We could use the following two commands, but considering that deleting is irreversible we should make sure we don’t delete the files by mistake. We will first list the contents using ls -l to make sure that we know which files are being deleted, and only then we run the rm command.

find / -type f -name *.txt -size +1M -exec ls -l {} \;
find / -type f -name *.txt -size +1M -exec rm -f {} \;

Another use case is moving files to other directories. Below we do the same, we use find in order to look for every text file in our starting directory. We execute the mv command, using the argument placeholder {} and we move each of those files to the /path/to directory.

find / -type f -name "*.txt" -exec mv {} /path/to \;

Below we do the same search but the execution function compresses each file individually using tar. We use the czf options for archive-creating and the name {}.tar.gz, the {} will be replaced by the current file’s name. Basically with the snippet below we create a compressed archive for each text file found based on provided criteria.

find / -type f -name "*.txt" -exec tar czf {}.tar.gz {} \;

We could even run a custom script. We retrieve the same files as before and for each file we execute the myscript.sh, which depending on the context can perform various actions.

find / -type f -name "*.txt" -exec /path/myscript.sh {} \;

Another basic argumentation for searching the files can be using -user filter in which we specifically search for the files owned by a specific user. The exec command below finds all the files owned by a specific user and for each individual file, it runs the chmod command which changes the file permission by adding reading and writing permissions.

find / -type f -user thedukh -exec chmod u+rw {} \;

What we have below is another really interesting example. Starting in the home directory, we look for all the regular files. For every file found, we use -exec and we invoke the shell sh with the -c param to execute the specified command. We execute the echo with the parameter expansion ${0##*.} in order to remove everything before the last dot in the filename, and we pipe this whole output, | sort | uniq -c, sorting it and counting unique instances.

find /-type f -exec sh -c 'echo "${0##*.}"' {} \; | sort | uniq -c

We could use xargs with find for parallel execution. Xargs is a command that allows us to build and execute commands from the standard input. It is used as a mediator of sorts because it takes input from a pipeline and passes it as an argument to another command.

What happens below is that again we look for all the .txt files, and we print the names to standard output using -print0. We use this command to properly handle filenames in our script. Next, we pipe the output (or the list of names) into the next command, which is xargs. Xargs will take these inputs and will convert them into arguments for another command. The important configuration here is the -P 4 which specifies that up to 4 commands can be run in parallel, which means that we are compressing multiple files (4) at the same time.

find / -type f -name "*.txt" -print0 | xargs -0 -P 4 -I {} gzip {}

Conclusion

In essence, the find is robust, flexible, and has wide uses for navigating and managing the file system in Unix-like operating systems. Hope you liked some of the examples above.