Things You May or May Not Know About Linux “find” Command

Sometimes it’s tough to make choices.

Take, the Unix command-line tool, for example. Everybody has a favorite, and it’s not easy to choose the most valuable. However, “find” would be a strong contender in such a decision. It is probably one of the first commands you learn to use as a Linux/Unix sysadmin, but it has so many options that you might still learn about — even if you’re an old pro at using Linux (or any other Unix-flavored OS).

In this post, Monitis will show you some of the more interesting options of using “Find.” It’s all part of our continuing effort to help make your life as a sysadmin easier, less taxing and richer in experience.

1. How to use “Find”

Let’s look at this command:

find /home -mount -iname “read*me” -delete

After this command, on the same UNIX system, you have to provide a search path, for example, “/home.” You also have to provide an expression that consists of options (i.e. -mount to search only on a given filesystem or -maxdepth to limit the depth of searches path), and you also must provide a set of test types (i.e. -name or -type) followed by related search term (i.e. apache for name or “d” for directory in the -type test). The last part of the expression, which is optional on Linux but not on some other UNIX systems, is an action, for example, “-print,” “-delete” or “-exec.” Before the path you can add some additional options, for example, to control debug, optimization or the way you handle symlink).

In this and the next two articles, we are going to concentrate on the heart of the “find” command: Test types. They are grouped by search term, for example, file name, time related information, permission, ownership etc.

2. Search for file name

One of the most common ways of using “find” is to search for files with a specific string in the name. The most popular test is “-name,” but there are a few others.

  • -name pattern – as mentioned above, it doesn’t have to be an exact name, because you can use a pattern based on shell wildcards: *, + and grouping in characters.

For example  the following command finds all files with the first letter “e” or “f” and last one x in /usr/bin directory:

find /usr/bin -name [ef]*x
  • -iname pattern – The above test is very useful, but it is case sensitive, and it can cause writing an improper pattern. In such a situation -iname might be the right choice. Adding ‘i’ in front of “name” makes the pattern case insensitive. It can help you, for example, to create a list of a file with the word “Centos” in the name (it could be Centos, CentOS, centos …)
find /usr -iname centos

Another interesting example might be to find all JPGs on a windows partition:

find /win/C -iname *JPG
  • -path pattern (or -wholename pattern) – Let’s say that you need to confirm that the file was created on 200 servers, and there is a random string in the path. You can use a script making many parallel ssh connections to execute the following command:
find / -path /usr/lib/important/*/file.txt

The next example is a bit academic, but it is another illustration of shell patterns usage. It prepares the list of all samba files in /var/log /var/lib (To be precise, in any /var sub-directory staring with “l” and having a three-letter name.)

find  /var -path */l??/samba*
  • -iwholename pattern  – this option is the equivalent of the -iname for a path (case insensitive search). Please remember that -ipath is a deprecated option.
  • -regex pattern – allows you to use regular expression with the find command. The shell wildcards mentioned above are very nice and useful, but one of the best tools of any sysadmin is the regular expression. By default, find understand Emacs Regular Expressions. However, it can be changed by the -regextype option.

If you haven’t been using regular expression, the short introduction in this link might be a good starting point. Please remember that regular expressions match the whole path — not a file name only. Therefore, the three-line command below should give different results. The first one shouldn’t return anything (the whole path started with grep), the second — the manual pages for everything having grep in the name, and finally the last one — only the grep man page.

find /usr/share/man/ -regex grep.*
find /usr/share/man/ -regex .*grep*
find /usr/share/man/ -regex .*/grep*
  • -iregex pattern – makes regular expression case insensitive.

Finally, below are two not-so-popular tests, which allow you to  search based on symbolic link destination:

  • -lname pattern – searches for  symbolic links whose destination (content) match the shell pattern. For example to find all link leads to the java plug-in you can try the following command:
find /usr/ -lname *javaplugin*
  • -ilname pattern -as above but case insensitive.

Appendix. Locate

Another useful command for searching files is to search by its name. That command is “locate,” or its secure version is “(s)locate.” It works a bit different from “find,” in that rather than searching a filesystem, (s)locate uses the database. The main advantage of the locate is speed:

Using the command find /var -name lighttpd, takes 0.731ms on a tested desktop, when using locate /var/*lighttpd*, only takes 0.139ms.

On the other hand, it might use outdated information, and to update the default database, you have to have superuser (root) privileges.

The locate searches can be case insensitive (-i), use regex (-r), and by default it uses wildcards, which are necessary if you want to restrict your search to define directory, i.e.:

locate /var/*cups*

To find all files having cups in the name in /var, you have to put * before and after the string you want find. Compare for yourself the results of:

locate /var/*cups* (on my system 104 files),
locate /var/*cups  (on my system 4 files).