Knowing how to use command line find
will help you search for files and directories quickly. Below are the things that will be covered:
Here are some advantages find has:
find
more convenient (pun intended).You don't have to learn every single feature to be productive, just learn the important ones. I believe Pareto's Principle (80/20 law) applies here: learning 20% of find
's feature should cover 80% of use cases.
Here is the basic syntax:
find location options
For 95-99% of my usage, I use .
for location (current directory). find
will use current directory as starting path and search recursively. You can use absolute or relative path location, like /Users/iggy/projects/
or ./projects
.
Let's talk about options. There are two important options: -name
and -path
. I think you can get a lot of milage with these two. When describing name and path, you can use basic patterns: [
, ]
, *
, and ?
(there are more patterns). Note that they are not regex. I will explain them later, but just want to keep in mind.
For more information about patterns, check this out.
# Find by NameThe -name
option means the last component of pathname. If I want to search all files containing the name "model.rb?":
find . -name "model.rb"
This returns everything that matches "model.rb" exactly. But what if we want to search for "user_model.rb", or "address_model.rb"? To find everything that contains "model.rb", we can use wildcard (*
) pattern to match zero or more characters.
find . -name "*model.rb"
To find anything containing the word "address":
find . -name "*address*"
Note: -name
does not mean file name. It could return a directory name. If I have an address directory (./src/components/address/
), find
it will return this directory too.
Recall that -name
searches for the last component of pathname. To find by anything in the path, we use -path
.
To find all files/directories inside "controllers":
find . -path "*controllers*"
By the way, if you do
find . -path "*controllers"
It returns just the "controllers" directories.
Find treats forward slash (/
) as normal characters. If you are looking specifically for "client/components":
find . -path "*client/components*"
It returns all path containing client followed by components
If you need to search for either "model", "modal", or "modes", you can use ?
to match any one character.
find . -path "*mod??"
This will match "mod", followed by any two characters (model/modal/modes). Remember, ?
is not a regex pattern (in regex ?
means 0 or more). Here it means any one character.
If you just want to search for either model or modal, you can do:
find . -path "*mod[ae]l"
[...]
matches exactly any one character enclosed. In addition, you can give it a range like [a-z]
, [A-Z]
, or [0-9]
. You can also mix the ranges [a-zA-Z0-9]
.
If you have "modalA", "modalB", ... "modalZ" and "modal0", "modal1", ... "modal9" and you want to return only the paths with a-z suffix (you do not want to search for numbers):
find . -path "*modal[^0-9]"
Adding ^
as first character inside [...]
negates the match inside []
. This means "give me anything EXCEPT modal that ends with 0-9".
find . -name "*email*" -or -name "*address*"
This searches for either "email" or "address". You can mix and match any options, like name or path. You can also use parentheses to group the conditions:
find . -name "*email.rb" -or \( -path "*deserializers*" -name "*address*" \)
This searches either:
email.rb
, or address
.find . -not -name "*address*"
Keep in mind that order matters. -not
must be followed by an option. find . -name -not "*address*"
won't work because -not
is placed after -name
.
We can also use !
instead of -not
.
So far when we search we have been getting results for either files of directories. What if we we want to search for only files or only directories?
We can filter it with -type
option.
-type d
-type f
There are more file types ("block special", "character special", "symbolic link", "FIFO", "socket"), but I think files and directories are the two that are used most.
To find all files containing "model" in path, we do:
find . -type f -path "*model*"
To search all directories containing the word "model" in its path:
find . -type d -path *model*
# RegexFind also accepts -regex
option:
find . -regex ".*address.rb"
Note that when we're using regex, find
matches against the entire relative path. What this means is, find returns matches with relative path (./
), for example:
./src/client/whatever.js
./src/client/frontend/
./server.js
Keep this pattern in mind when you are describing your regex.
# Find by Size You can find files based on their file size (rounded up 512b):find . -size +1M
Finds files 1 Megabyte or greater.
Here are different file size options that find
accepts:
k kilobytes (1024 bytes)
M megabytes (1024 kilobytes)
G gigabytes (1024 megabytes)
T terabytes (1024 gigabytes)
P petabytes (1024 terabytes)
# Execute Command LineSometimes it is not enough to just find files. Sometimes we need to execute command line commands into our find results. Find has -exec
command for that. Let's look at some examples:
find . -name "*model.rb" -exec cat {} ";"
find . -type d -path "*model*" -exec ls -l {} ";"
You can also chain multiple execs together
find . -name "*model.rb" -exec grep -q to_hash {} ";" -exec cat {} ";"
This searches for all results containing "model.rb" in their path's last component, run grep quietly (-q
) to look for lines containing "to_hash" string, then cat
these files.
-exec
is a useful feature to learn. To learn more about -exec
, here are some resources to get started:
find
Thanks for reading. Happy coding!
# Resources - `man find` - [How do I find a file by filename in Mac OSX terminal?](https://superuser.com/questions/226566/how-do-i-find-a-file-by-filename-in-mac-osx-terminal) - [Find Command: File Path vs -name Argument](https://unix.stackexchange.com/questions/171065/find-command-file-path-vs-name-argument) - [Shell Pattern Matching](https://www.gnu.org/software/findutils/manual/html_node/find_html/Shell-Pattern-Matching.html) - [How to use regex with find command? ](https://stackoverflow.com/questions/6844785/how-to-use-regex-with-find-command)