= Find files with find

The `find` command is one of the most useful Linux commands, especially when faced with the hundreds and thousands of files and folders a modern computer contains.
As its name implies, `find` helps you find things, and not just by filename.
Whether you're on you're own computer or you're trying to support someone on an unfamiliar system, here are X things you can do with `find` to help you locate important data.

== 1. Find a single file by name

When you know the name of a file, but you can't remember where you saved it, use `find` to search your home directory.
Use `2>/dev/null` to silence permission errors (or use `sudo` to gain all permissions).

[source,bash]
----
$ find / -name "Foo.txt" 2>/dev/null
/home/seth/Documents/Foo.txt
----

== 2. Find a single file by approximate name

If you can't remember the exact name of the file, or you're not sure whether something was capitalized or not, you can do a partial and case-insensitive search:

[source,bash]
----
$ find / -iname "*foo*txt" 2>/dev/null
/home/seth/Documents/Foo.txt
/home/seth/Documents/foo.txt
/home/seth/Documents/foobar.txt
----

== 3. Find everything

An interesting alternative to `ls -R`:

[source,bash]
----
$ find ~/Documents -ls
3554235 0 drwxr-xr-x 2 seth seth 54 Sep 14 05:36 /home/seth/Documents/
3554224 0 -rw-rw-r-- 1 seth seth  0 Sep 14 05:36 /home/seth/Documents/Foo.txt
3766411 0 -rw-rw-r-- 1 seth seth  0 Sep 14 05:36 /home/seth/Documents/foo.txt
3766416 0 -rw-rw-r-- 1 seth seth  0 Sep 14 05:36 /home/seth/Documents/foobar.txt
----

Notice that I don't use `2>/dev/null` in this instance, because I'm only listing the contents of a https://redhat.com/sysadmin/absolute-path-and-relative-path-linux[file path] within my home directory, so I don't anticipate permission errors.

== 4. Find by content

A `find` command doesn't have to perform just one task.
In fact, there's an option in `find` that enables you to execute a different command on whatever results `find` returns.
This can be especially useful when you need to search for a file by *content* rather than by name, or you need to search by both.

[source,bash]
----
$ find ~/Documents/ -name "*txt" -exec grep -Hi penguin {} \;
/home/seth/Documents/Foo.txt:I like penguins.
/home/seth/Documents/foo.txt:Penguins are fun.
----

== 5. Find files by type

Using the `-type` option, you can find files, directories, symlinks, named pipes, sockets, and more.

[source,bash]
----
$ find ~ -type f
/home/seth/.bash_logout
/home/seth/.bash_profile
/home/seth/.bashrc
/home/seth/.emacs
/home/seth/.local/share/keyrings/login.keyring
/home/seth/.local/share/keyrings/user.keystore
/home/seth/.local/share/gnome-shell/gnome-overrides-migrated
[...]
----

As long as you're using the GNU version of `find`, you can include multiple file types in your search results:

[source,bash]
----
$ find ~ -type f,l -name "notebook*"
/home/seth/notebook.org
/home/seth/Documents/notebook-alias.org
----

== 6. List just directories

A shortcoming of the `ls` command is that you can't filter its results by file type, so `ls` can be noisey if you only want a listing of directories in a path.
The `find` command combined with the `-type d` option is a better choice:

[source,bash]
----
$ find ~/Public -type d
find ~/Public/ -type d
/home/seth/Public/
/home/seth/Public/example.com
/home/seth/Public/example.com/www
/home/seth/Public/example.com/www/img
/home/seth/Public/example.com/www/font
/home/seth/Public/example.com/www/style
----

== 7. Limit listing results

With hundreds of files in even a default user directory, and thousands more outside of that, sometimes you get more results from `find` than you want.
You can limit the depth of searches with the `-maxdepth` option, followed by the number of directories you want `find` to descend into after the starting point:

[source,bash]
----
$ find ~/Public/ -maxdepth 1 -type d
/home/seth/Public/
/home/seth/Public/example.com
----

== 8. Find empty files

Sometimes it's helpful to find empty files as a way to declutter:

[source,bash]
----
$ find ~ -type f -empty
random.idea.txt
----

Technically, you can use `find` to remove empty files, but programmatic removal of files is dangerous.
For instance, forget to include `-type f` in a search for empty _files_ and you get directories in your results, so by adding a delete flag you would remove potentially important directory structures.
It's vital to compose your `find` command and then verify the results before deleting.
Furthermore, a misplaced delete flag in `find` can delete results before qualifying them (in other words, you can delete directories in a command intended to delete only files by placing the delete flag before the type flag.)
I prefer to use `xargs` or http://LINK-TO-PARALLEL-ARTICLE[parallel] and a https://www.redhat.com/sysadmin/recover-file-deletion-linux#trashy[trash command] on the rare occasion that I remove files with `find`.

== 9. Find files by age

The `-mtime` option allows you to limit a search to files older than, but also files newer than, _some value_ times 24.

[source,bash]
----
$ find /var/log -iname "*~" -o -iname "*log*" -mtime +30
----

The `+` before the `-mtime` number doesn't mean to add that number to the time, it's a conditional statement that matches (in this example) a value _greater than_ 24 times 30.
In other words, the sample code finds log files that haven't been modified in a month or more.

To find log files modified within the past week, you can use the `-` conditional:

[source,bash]
----
$ find /var/log -iname "*~" -o -iname "*log*" -mtime -7
/var/log/tallylog
/var/log/cups/error_log
/var/log/cups/access_log
/var/log/cups/page_log
/var/log/anaconda/anaconda.log
/var/log/anaconda/syslog
/var/log/anaconda/X.log
[...]
----

You already know about the `-ls` flag, so you can combine that with these commands for clarity:

[source,bash]
----
$ find /var/log -iname "*~" -o -iname "*log*" -mtime -7 -ls
-rw-------  1 root root            0 Jun  9 18:20 /var/log/tallylog
-rw-------  1 root lp      332 Aug 11 15:05 /var/log/cups/error_log
-rw-------  1 root lp      332 Aug 11 15:05 /var/log/cups/access_log
-rw-------  1 root lp      332 Aug 11 15:05 /var/log/cups/page_log
-rw-------  1 root root  53733 Jun  9 18:24 /var/log/anaconda/anaconda.log
-rw-------  1 root root 835513 Jun  9 18:24 /var/log/anaconda/syslog
-rw-------  1 root root  21131 Jun  9 18:24 /var/log/anaconda/X.log
[...]
----

== 10. Searching a path

Sometimes you know the directory structure leading up to a file you need, you just don't know where the directory structure is located within the system.
To search within a path string, you can use the `-ipath` option, which treats dots and slashes not as regex characters, but as dots and slashes.

[source,bash]
----
$ find / -type d -name 'img' -ipath "*public_html/example.com*" 2>/dev/null
/home/tux/Public/public_html/example.com/font
----

== Found it

The `find` command is an essential tool for a sysadmin.
It's useful when investigating or getting to know a new system, for finding misplaced data, and for https://www.redhat.com/sysadmin/find-best-friend[troubleshooting] everyday problems.
But it's also just a convenience tool.
You don't need a "good" reason to use `find`.
If it makes a task easier to just search for something instead of traversing your system, then use `find`.
It's an understated but infinitely useful tool that embodies the sublime pleasure of everyday Linux.
Start using it today, and _find_ out what makes it great.
