How to Use Command Line Find
Tags: find, linux, search, commandline
Published: 2020-04-03 22:29:07

---
title: How to Use Command Line Find
published: true
description: How to use command line find to search for files
tags: find, linux, search, command-line
---

Knowing how to use command line `find` will help you search for files and directories quickly. Below are the things that will be covered:

- [Why Learn Find](#why)
- [Syntax and Patterns](#syntax)
- [Find by Name](#name)
- [Find by Path](#path)
- [Or](#or)
- [Not](#not)
- [Find File / Directory Only](#type)
- [Regex](#regex)
- [Find by Size](#size)
- [Execute Command Line](#exec)
- [Conclusion](#conclusion)
- [Resources](#resources)


<a name="why"></a>
# Why Learn Find
Why do we need to learn find? Can't we just use tools like [ripgrep](https://github.com/BurntSushi/ripgrep), [ag](https://github.com/ggreer/the_silver_searcher), or browse through GUI manually?

Here are some advantages find has:
1. It is found in most terminal.
2. Searching from GUI can be tedious and hard to filter.
3. Although ripgrep and ag may have better features than find, they are not universally available. If you work with remote servers, you may *find* `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.

<a name="syntax"></a>
# Syntax and Patterns

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](https://www.gnu.org/software/findutils/manual/html_node/find_html/Shell-Pattern-Matching.html).

<a name="name"></a>
# Find by Name

The `-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.

<a name="path"></a>
# Find by Path

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".

<a name="or"></a>
# Or
To search for either A or B, `find` has an `-or` option:

```
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:
- Files that end with `email.rb`, or 
- Files/directories containing "deserializers" in its path and name containing `address`.

<a name="not"></a>
# Not
What if we want to search for everything except "address"? Find accepts `-not`, we can do:

```
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`.

<a name="type"></a>
# Find File / Directory Only

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.

- For directory, w use `-type d`
- For file, we use `-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*
```


<a name="regex"></a>
# Regex

Find 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.


<a name="size"></a>
# 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)
```


<a name="#exec"></a>
# Execute Command Line

Sometimes 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:

- [Linux shell, how to use the exec option in find with examples](https://linuxaria.com/howto/linux-shell-how-to-use-the-exec-option-in-find-with-examples)
- [find -exec with multiple commands](https://stackoverflow.com/questions/5119946/find-exec-with-multiple-commands)
- [Understanding the -exec option of `find`](https://unix.stackexchange.com/questions/389705/understanding-the-exec-option-of-find/389706)

<a name="conclusion"></a>
# Conclusion
I think this is a good place to stop. This knowledge should be sufficient to get you started and be productive. I cannot recommend `man find` enough. There are many more useful options that I didn't mention here. Experiment with different command lines, use it everyday, and more importantly, have fun!

Thanks for reading. Happy coding!

<a name="resources"></a>
# 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)