find Command Examples
The find command is used for searching for files and directories in the Linux command line.
Find is one of the most powerful and frequently used commands. It is also one of the most extensive commands with over 50 options and this makes it a bit confusing, specially when it is paired with the exec or xargs command.
It is impossible for a sysadmin or software developer to avoid the find command while working in the command line. Instead of being afraid of it, you should embrace its power.
I am going to discuss some of the most common examples of the find command that you are likely to use. But before that, let me show you its syntax and how to use it.
Find command syntax
The general syntax for the find command is:
find [directory to search] [options] [expression]
Everything in brackets [] are optional. It means that you can run find
command without any options and arguments. It will just dump all the files and directories in the current location. That's not very useful, right?
Let's look at it in more detail:
directory to search
is basically the location from where you want to start your search. By default, the search is recursive and starts from your current location.options
specify the type of search, be it by name, by type, by modified time etc. There are more than 50 options possible here.expression
allows you to specify the search term. If you want to find a file by its name, expression is the file name. If you want to find files with name matching a pattern, expression in the pattern.
Let me take a simple example:
find . -type f -name myfile
This command will run a search in the current directory and its subdirectories to find a file (not directory) named myfile
. The option -type f
asks it to look for files only. The single dot .
means the current directory.
Let's see some practical examples of the find command.
Find files and directories by name
You can search for files and directories by its name:
find . -name SEARCH_NAME
Since there is no file type mentioned, it searches for both files and directories with the given name.
The below example finds both file and directories named mystuff:
abhishek@LHB:~/Examples$ find -name mystuff
./new/mystuff
./mystuff
Find only files or only directories
If you only want to look for files, specify file type -f:
find . -type f -name SEARCH_NAME
The order of type and name does not matter. Take the previous example and find for files only:
abhishek@LHB:~/Examples$ find -type f -name mystuff
./mystuff
If you only want to search for directories, specify type -d:
find . -type d -name SEARCH_NAME
In the previous file, look for directories only:
abhishek@LHB:~/Examples$ find -type d -name mystuff
./new/mystuff
Run a case-insensitive search
By default, the find command is case sensitive. You can run a case-insensitive search with the given name by using -iname
instead of -name
.
find . -type f -iname SEARCH_NAME
You can use it with type d
as well.
abhishek@LHB:~/Examples$ find -iname mystuff
./new/mystuff
./MyStuff
./mystuff
Screenshot of the above three examples:
Search files by their extension (important)
One of the most common use of the find command is to find files of a specific type or should I say a specific extension.
For example, let's say, you want to search for all the C++ files in the current directories. The C++ files end with extension .cpp, so you can search it like this:
find . -type f -name "*.cpp"
This way, you tell the find command to look for type file
and with names that end with .cpp
.
abhishek@LHB:~$ find . -type f -name "*.cpp"
./file.cpp
./.cargo/registry/src/github.com-1ecc6299db9ec823/libz-sys-1.1.3/src/zlib/contrib/iostream2/zstream_test.cpp
./.cargo/registry/src/github.com-1ecc6299db9ec823/libz-sys-1.1.3/src/zlib/contrib/iostream/test.cpp
./.cargo/registry/src/github.com-1ecc6299db9ec823/libz-sys-1.1.3/src/zlib/contrib/iostream/zfstream.cpp
Why do I recommend using double quotes or single quotes around your search term? Because if you do not do that, the shell will expand the wildcard.
If you do not wrap your search term in quotes:
find . -type f -name *.cpp
Your shell will expand *.cpp and replace it with all the files in the current directory whose names end with .cpp.
This could work if there is only one file but if there are more than one, your shell will complain of incorrect syntax.
In the above example, there is only one cpp file and hence when the command expands to find . -type f -name file.cpp
, it works because it file.cpp
still works as search term.
But there are two .txt files in the same directory and hence when the command expands to find . -type f -name another.txt new.txt
, it complains because there is more than one search term now.
This is why you should always wrap your search term in double quotes.
Search for multiple files with multiple extensions (or condition)
The above command searched for files with a given extension. What if you want to look for files with different extensions?
Instead of running the find command multiple times, run it once by using the -o
option that works as logical OR condition:
find . -type f -name "*.cpp" -o -name "*.txt"
Here's an example:
abhishek@LHB:~/Examples$ find . -type f -name "*.txt" -o -name "*.cpp"
./new.txt
./file.cpp
./new/new.txt
./new/dir2/another.txt
./new/dir1/new.txt
./another.txt
Look for files in a specific directory
So far, all the examples performed search in the current directory because you specified .
in the examples.
The dot can be replaced with an absolute or relative path of a directory so that you can look for files in the specified directory without leaving your current location.
abhishek@LHB:~/Examples$ find ./new -name mystuff
./new/mystuff
Search for files in multiple directories
If you think your desired file(s) could be located in several locations, you don't have to run find command multiple times. Just specify all the directory paths to search in the find command:
find ./location1 /second/location -type f -name "pattern"
Find empty files and directories
The -empty
option enables you to look for empty files and directories with the find command.
To find all the empty files and directories in the current directory, use:
find . -empty
You can specify the file type to look only for empty files or directories:
find . -empty -type f
You may also combine it with the filename search:
find . -empty -type f -name "*.cpp"
Find big files or small (Search based on file size)
You can find big files or small files based on the search performed by the size parameter. This only works with files, not directories.
You use the -size
option with +N for size greater than N and -N for size smaller than N.
Find files of exactly 50 KB in size:
find . -size 50k
To search for files bigger than 1 GB in the current directory:
find . -size +1G
To find smaller than 20 bytes:
find . -size -20c
To find files bigger than 100 MB but smaller than 2 GB in size:
find . -size +100M -size -2G
You may also combine the size search with the name search. For example, to search for all files with name ending in .log but size greater than 500 MB in the root directory, you can use:
find / -size +500M -name "*.log"
To recall:
c
: bytesk
: kilobytesM
: MegabytesG
: Gigabytes
Find recently modified files (Search based on modify or creation time)
You know the concept of mtime, atime and ctime, right?
- mtime: last modification time of file
- ctime: creation time of the file
- atime: last access time of the file
You'll often find yourself in situations where you want to find all the recently modified files. The search by modified time helps in such cases.
To find all the files modified within 3 days (3*24H), use:
find . -type f -mtime -3
To find all the files created at least 5 days (5*24H) ago, use:
find . -type f -ctime +5
I know 24 hours is a huge time frame. What if you want to search for files that were modified only a few minutes ago? For that, you can use mmin
, amin
and cmin
.
To find all the files that were modified in the last 5 minutes, use:
find . -type f -mmin -5
You can specify upper and lower limits along with the search name. The command below will search for all the .java files that have been modified between last 20 to 30 minutes.
find . -type f -mmin +20 -mmin -30 -name "*.java"
Find files with specific file permissions
I hope you are familiar with the file permission concept in Linux.
The find command allows you to search for files with specific file permission and access mode.
find -perm mode
For example, to find all the files access mode 777 in the current directory;
find . -perm 777
To find all files with access of read and write for all (exact match, it won't match if the file has execute permission for all):
find . -perm a=r+w
Find files owned by a user
You can also search for files based on ownership.
For example, to find files owned by the user John in the current directory, use:
find . -type f -user John
You can also combine it with other options like size, time and name:
find . -type f -user John -name "*.cpp"
Don't find recursively, search only in current directory
By default, the find command searches recursively in all the subdirectories of your current location. If you don't want that, you can specify the depth of your search to 1. This will restrict the search to only the current directory and excludes any subdirectories.
find . -maxdepth 1 -type f -name "*.txt"
Exclude a directory from search
if you want to exclude a directory from the search, you can do that by combining path, prune and logical or.
find . -path "./directory_exclude/*" -prune -o -name SEARCH_NAME
Be careful with the * in the path of the directory, -prune
after path and -o
after prune.
Basically, the prune command asks to not use the value specified by path. Prune is always used with -o
to ensure that right side of the terms are evaluated only for directories that were not pruned.
Take action on the result of find commands (exec and xargs)
So far, you have learned various ways to find files based on various criteria. That's good. But you can make it better by taking certain actions on the result of the find command.
For example, how about finding files matching certain name pattern and renaming them all at once or finding empty files and deleting them?
You know that pipe redirection can be used to combine the output of one command with the input of another command. But this won't work with the output of find command, at least not directly.
You have two options if you want to take an action on the result of find command:
- Use exec
- Use xargs
Using find and exec
Suppose you want to long list (ls -l) the search files with the find command. Here's what you use:
find . -type f -name "*.txt" -exec ls -l {} +
Here's the output:
abhishek@LHB:~/Examples$ find . -type f -name "*.txt" -exec ls -l {} +
-rw-rw-r-- 1 abhishek abhishek 39 Oct 13 19:30 ./another.txt
-rw-rw-r-- 1 abhishek abhishek 35 Oct 13 15:36 ./new/dir1/new.txt
-rw-rw-r-- 1 abhishek abhishek 35 Oct 13 15:36 ./new/dir2/another.txt
-rw-rw-r-- 1 abhishek abhishek 35 Oct 13 18:51 ./new/mystuff/new.txt
-rwxrwxrwx 1 abhishek abhishek 35 Oct 13 15:37 ./new/new.txt
-rw-rw-r-- 1 abhishek abhishek 35 Oct 13 18:16 ./new.txt
Many people forget to add the {} +
at the end of the exec command. You must use it and mind the space between {} and +.
The {} is what references the result of the find command. You can imagine it to be like {file 1, file 2, file 3}. The +
sign is used to terminate the exec command.
There is also another convention with exec:
find . -type f -name *.txt" -exec ls -l {} \;
Here, ; is used instead of the + sign. The additional \ before ; is used to escape the special character ;.
The advantage of {} +
is that it runs fewer commands as ls -l file1 file2 file3
whereas {} \;
will run ls -l file1
, ls -l file2
etc.
But, {} \;
has the advantage of using {}
more than once in the same exec statement. For example, the command below will rename all the found files with .old extension.
find . -type f -name *.txt" -exec mv {} {}.old \;
Using xargs
Many Linux users get used to of the pipe redirection. This exec command with the trailing {} +
seems intimidating to them.
This is where xargs helps. You just parse the output of the find command to the xargs command via pipe.
find . -type f -name *.txt" | xargs ls -l
The syntax seems a lot simpler, right? Xargs command is also very powerful. You may read about it here.
Combining find and grep
Now that you know about combining find with exec and xargs command, you can use it to combine find and grep.
For any sysadmin or software developer, find and grep is one of the most common and yet most useful combination.
You search for file name patters with find and then use grep to search for the content inside those files.
For example, you want to search for all the .txt files that contain the term Alice. You combine find and grep like this:
find . -type f -name "*.txt" -exec grep -i alice {} +
The same can be achieved with xargs as well:
find . -type f -name "*.txt" | xargs grep -i alice
Of course, this is the simplest of the examples but if you are familiar with the grep command, you can use it to your liking and need.
💡 Bonus Tip: Avoid seeing 'permission denied' errors
When you run the find command on the root directory, you'll see a lot of 'permission denied' error in the output. That's because you don't have the rights to enter many directories owned by the root user.
So, what can you do? You can use sudo or you can redirect the errors to /dev/null and this way, you won't see those errors on the screen.
find / -type f -name skypeforlinux.png 2>/dev/null
The errors will still be encountered, they just won't be displayed as you redirected them to /dev/null instead of stdout.
There is a lot more with find ...
And it is not possible to list all the find command options and examples. The possibilities are endless but when you get familiar with the find command, you can start using it in a variety of situations. That is really up to you how you combine the logic here.
I hope you find these examples of find command useful. If you still have questions or suggestions to improve this article, please let me know in the comment section.