Last updated:
The find
utility is used to search for files. As finding files is an important and common task the utility has a very large number of options. This article aims to give you and overview of how you can use find
, and we will throw in a few tips and tricks along the way.
As an aside, when we talk about files in Linux we usually talk about any type of file, including directories, symbolic links and even sockets (as everything in Linux is a file). You can of course use find
to find directories, as we will see very shortly.
Before we look at the utility’s options we should mention that you can run find
without any options. Just entering find
displays all files (including directories and hidden files) below the currently directory. You can easily test this yourself by creating some directories and files:
$ mkdir css $ touch index.html .gitignore css/global.css $ find . ./css ./css/global.css ./.gitignore ./index.html
The above example shows that, by default, find
searches recursively from the current directory. The find
command we just ran is therefore identical to the command find .
(or, if you prefer, find ./
).
The -maxdepth
option limits how far find
descends into the directory tree. If you want to limit your search to just the current working directory then you can use -maxdepth 1
:
$ find -maxdepth 1 . ./css ./index.html ./.gitignore
And if you want to include one level of subdirectories then you can change the value to 2:
$ find -maxdepth 2 . ./css ./css/global.css ./index.html ./.gitignore
As you can see, the second command also found files inside the css directory.
If you want find
to return more than just file names you can add -ls
at the end of your command. It seems counter-intuitive to add -ls
at the end of the command but there is a logical reason: it is an expression rather than an option. The expression tells find
what should be done with found files. The -ls
expression shows a detailed listing. There are a few other common options, including -delete
and -exec
. We will encounter them later, but first we should look at -ls
:
$ find ./ -ls 1694651881 0 drwx------ 3 example example 72 Sep 22 01:40 . 144431381 0 drwx------ 2 example example 23 Sep 22 01:30 ./css 144431384 0 -rw-r--r-- 1 example example 0 Sep 22 01:30 ./css/global.css 1694651888 0 -rw-r--r-- 1 example example 0 Sep 22 01:23 ./.hidden 1694651890 0 -rw-r--r-- 1 example example 0 Sep 22 01:30 ./index.html 1694651891 0 -rw-r--r-- 1 example example 0 Sep 22 01:30 ./.lvimrc 1694651895 4 -rw-r--r-- 1 example example 475 Sep 22 01:40 ./find
The output includes the inode number and is therefore similar to the output you get with ls -liR
.
The -name
option lets you search for files by name. You can use globbing:
$ find ./ -name index.htm* ./index.html
The above command searches for files matching the pattern index.htm*
. The asterisk is a “glob” that matches zero or more characters. So, index.htm* matches index.html (and it would also match index.htm).
Also, the -name
option is case-sensitive. You can do a case-insentitive search using the -iname
option.
The -type
option searches for files by type. The most common types are regular files (f
) and directories (d
):
$ find -type f -name .gitignore ./.gitignore $ find -type d -name css ./css
The -size
option lets you search for files by size. The most common file size units are k
(kilobytes), M
(megabytes) and G
(gigabytes). By default, the -size
option searches for files of exactly the specified size, which isn’t all that useful. You can search for files that are smaller or larger than a certain size using the minus (-
) and plus (+
) signs. For example, the below command finds files larger than 1GB in the /home/example directory:
$ find /home/example/ -size +1G /home/example/backups/backup_20210101.tar.gz /home/example/backups/backup_20210201.tar.gz …
The -user
and -group
options let you search for files by ownership. This is useful to find files owned by a particular user or to check if files in a certain directory are as you expect. For example, you can retrieve files in a website directory owned by apache:
$ find /var/www/html/example.net/ -user apache /var/www/html/example.net/sites/default/files /var/www/html/example.net/sites/default/files/.htaccess …
You can make searches more specific using the -and
, -or
and -not
operators. In the below example we are looking for files that are not owned by apache and not owned by example. Rather than listing the files we pipe the output to wc -l
, which gives us a count of the number of lines returned by the command. There are zero lines, which in this case is good:
$ find /var/www/html/example.net/ -not -user apache -and -not -user example | wc -l 0
The -not
operator can be substituted by an exclamation mark (!
):
$ find /var/www/html/example.net/ ! -user apache -and ! -user example | wc -l 0
Another interesting option is -nouser
. As the name suggests, you can use this to find files that have no user (perhaps because the user has been deleted):
$ find ./ -nouser
The -perm
option lets you search for files by permission. You can use this to check if permissions are as you expect in, say, a website directory. Here, we search for directories (-type d
) that don’t have 750 permissions (! -perm 750
):
$ find /var/www/html/example.net/ -type d ! -perm 750 /var/www/html/example.net/sites/default/files …
You can also use the -executable
option to find files that are executable:
$ find /var/www/html/example.net/ -type f -executable | wc -l 0
The -ctime
, -mtime
and -atime
options let you search for files by timestamp:
You can search for files that have (or have not) been modified in the last x days by preceded the value with either a plus (+
) or minus (-
) sign. A plus sign returns files that have not been updated during the number of days you specify. You can use this to check if a directory contains old files that can be deleted. Here, we are checking a logs directory for files that are more than a year old:
$ find /home/example/logs/ -mtime +365 | wc -l 143
You can use the minus sign to find files that have recently been modified. For instance, you can search for files in your bin directory that have been modified in the last five days:
$ find bin/ -type f -mtime -5 bin/backup.sh
You can use the -cmin
, -mmin
and -amin
options if you prefer to specify minutes rather than days. For instance, if you just ran a chmod
command then you can check which files have been affected:
$ find ./ -cmin -1
In modern versions of Bash you can also specify dates using the -newermt
option. You can use the option instead of -mtime
:
$ find /home/example/backups/ -type f -name "*.tar.gz" ! -newermt "2021-01-01"
Here, ! -newermt "2021-01-01"
returns all files that are not newer than 1st January 2021. Note the exclamation mark, which negates the date passed to newermt
and therefore only returns files that do not match.
In the same way you can find files that were modified on a certain day. For example, to find files that were modified on the 9th September 2020 you can use two -newermt
options. The first specifies the date you want to find and the second uses the exclamation mark and the next day (in this case 10th September 2020):
$ find /home/example/ -type f -newermt "2020-09-09" ! -newermt "2020-09-10" -ls 1650859535 4 -rw-r--r-- 1 example example 3412 Sep 9 12:25 ./public-html/wp-config.php
Earlier, we talked about the -ls
expression. There are a few other common expressions. A common expression is -exec
. The expression is used to execute a command on the files found by find
. You need to specify the command you want to run (obviously) followed by a pair or curly brackets ({}
) and either an escaped semi-colon (\;
) or plus sign (\+
).
To illustrate, the following command finds files that have no owner. It uses -exec
to run the command stat "%U %n"
, which prints the owner and file name:
$ find ./ -nouser -exec stat -c "%U %n" {} \; UNKNOWN ./sites/default/files UNKNOWN ./sites/default/files/assets UNKNOWN ./sites/default/files/assets/images UNKNOWN ./sites/default/files/assets/images/blog
The curly brackets are a place-holder for the files retrieved by find
and the semi-colon indicates that there are no further arguments for the command. The semi-colon has to be escaped; otherwise the shell might expect a next command (because you can delimit multiple commands with semi-colons).
The above command is relatively ineffective because the stat
command (stat -c "%U %n"
) is executed on each file found by find
. In effect, it is executed like so:
stat -c "%U %n" ./sites/default/files stat -c "%U %n" ./sites/default/files/assets stat -c "%U %n" ./sites/default/files/assets/images stat -c "%U %n" ./sites/default/files/assets/images/blog
Piping the output from find
to xargs
would be more efficient as all the files would be passed to the stat
command as a string with file names. It is possible to do exactly that with -exec
by substituting the semi-colon with a plus sign:
$ find ./ -nouser -exec stat -c "%U %n" {} \+ UNKNOWN ./sites/default/files UNKNOWN ./sites/default/files/assets UNKNOWN ./sites/default/files/assets/images UNKNOWN ./sites/default/files/assets/images/blog
The output is exactly as before but the command is executed as a single command. In effect, it is run like so:
stat -c "%U %n" ./sites/default/files ./sites/default/files/assets ./sites/default/files/assets/images ./sites/default/files/assets/images/blog
Using -exec
with the plus sign is therefore largely identical to using xargs
. You can argue that -exec
uses a somewhat awkward syntax. However, a nice feature of -exec
is that you don’t have to worry about file names containing spaces. It is up to you to decide which of the following commands makes the most sense:
$ find ./ *.txt -exec file {} \+ $ find ./ *.txt -print0 | xargs -0 file
The -exec
option is often used to remove files, as in:
$ find ./ -type f -name *.bak -exec rm {} \+
A slightly better way of removing files is by using the -delete
expression. Using this option should be a little quicker for the reason that find
doesn’t have to call the external rm
utility.
$ find ./ -type f -name *.bak -delete
Hopefully, this article has given you a good idea of how you can use find
. To learn more, it is worth reading the man page. The best way to get comfortable with utilities such as find
is by using them though. You will quickly get familiar with the various options we covered, and you will almost certainly find other options that are relevant for your workflow.