Linux: Find File by Name

Linux has a powerful command called find. It can find any file (or directory), according to the search parameters we pass to it.

In this tutorial we'll explore how we can find files, based on their names.

Syntax of the Find Command

The syntax of the find command is:

find [options] [/path/to/directory/] [search_parameters]

The options can change the behavior of the find command. For example, there's an option -L that will make it follow symbolic links. A symbolic link is a sort of "shortcut" on Linux; a "fake" file that leads to a real file, or directory, that exists in a different location. Similar to a shortcut we might have on a Windows desktop, that opens up the real program when we double click it.

Often, find can be used without specifying any options. If we don't want any "advanced behavior," or fine-tuning of how the find command works internally.

With /path/to/directory/ we specify the path to the directory we want to search through. This is also optional. For example, if we want to search for files in the directory we are currently in, we can omit this path to the directory.

And the search parameters are what matters most in a find command. This is where we actually tell find what to search for.

We can specify one, or more parameters here. For example, we can tell find to search for files with some exact name. But we can also chain multiple parameters, and tell find to search for files that end with the .jpeg name, are at least 5 days old, and are larger than 10 megabytes.

Here's an example of a find command where all three of these arguments are used:

  • We'll use -L as an option. To make find follow symbolic links.
  • We'll specify the path to a directory, /usr/share/, to look for certain files here.
  • And the search parameter will be -name motd to find a file called motd (a template file for the Message of the Day we might see when we log in to Linux machines).
find -L /usr/share/ -name motd

The output we'll get from this command might look something like this:

/usr/share/motd
/usr/share/base-files/motd

This is the result list, where find shows us the full path to the matches it found: Files, or directories with this exact name, motd.

A common mistake when using the find command is to mix up the position of the path to the directory, with the position of the search arguments.

Meaning that a command like this is correct:

find /usr/share/ -name motd

But if we accidentally reverse the position of the path, with the search arguments, we end up with an incorrect command like this:

find -name motd /usr/share/

To solve this we can think of the find command usage as:

Find where, what.

Meaning "where" is the first thing we need to specify (where is the directory?). And "what" is the second thing we have to specify (what name, or properties?).

It's similar to real life. If we want to go to a store, first we have to go to a general location on a map (the where part). And only afterwards we go to the specific store (the what part).

Find File (or Directory) with Exact Name

If we know the exact name of the file, or directory we're looking for, things are quite simple.

For example, let's say the file we are looking for is called index.html. And it's somewhere in the /home/alex/ directory. To search for this all we need to do is run:

find /home/alex/ -name index.html

We can see it found the file at this path: /home/alex/template_projects/project1/.

It's important to remember that, by default, find will display both files, and directories with this name. For example, look what happens if we search for something called project1:

find /home/alex/ -name project1

Now it found two results. And we know that the first result, /home/alex/template_projects/project1/ is a directory, since we saw that in the previous example. But what is /home/alex/projects/project1? Is it a file, or directory? No way to know (just by looking at the result list), but we can solve this issue.

Search Only for Files with this Name

We can tell find to filter results, and only show us files, not directories. All we need to do is add another search parameter: -type f.

I'll create a directory called index.html just to exemplify this:

Here's what happens if we do a regular search, and tell our command to find anything with the name index.html:

find /home/alex/ -name index.html 

It shows us both the directory (first result), and the file (second result).

But now let's add -type f in our search parameters. Which tells find to filter results, and only show files in the result list:

find /home/alex/ -name index.html -type f

Now we get only the file in the result list. And the directory is excluded.

Search Only for Directories with this Name

We can also filter in the opposite way. Instead of telling find to only show us files, we can tell it to only show us directories. For that, we add -type d to our search parameters:

find /home/alex/ -name index.html -type d

And this time we get only the directory:

Now that we know how to filter our results, and search only for files, let's see what we can do when we don't know the exact name of a file.

Find File by Name Pattern

The simplest pattern is when we know the "extension" of a file. If a file has a name like image.jpeg we say that the extension of this file is .jpeg.

đź’ˇ
Note: Unlike Windows, Linux doesn't consider these extensions, but just a regular part of the name that happens to contain a . in there. But we're going to call them extensions here, just to use familiar terms.

Find File by Extension

Let's say we're looking for HTML files. That means we need to search for all files which have a name that ends with .html. And that's quite easy. All we need to do is use the * wildcard in our -name search parameter. We'll soon talk about what * does after we see an example.

In our scenario, to look for all files that end with the .html extension, we could run a command like this:

find -name '*.html' -type f

Note we didn't specify the path to the directory here. Just to offer an example that even that part is optional. Since we're already in the /home/alex/ directory, our find command will look for files in this current path. Of course, if we'd be in a different directory, we'd need to specify the full path here:

find /home/alex/ -name '*.html' -type f

There's a subtle difference in how we used the find command this time though. We wrapped the name pattern in single quotes ' '. Instead of *.html we used '*.html'. It's important to do this when using the * wildcard. That's because in Bash (the default command interpreter on most Linux systems), the * has a special meaning. And Bash would interpret it to mean something else rather than what we want here. It would replace * with all files and directories in the current path. And we don't want that.

So by wrapping between single quotes we tell Bash:

Do not interpret this *, just send it to the find command as a regular * (don't expand it to all files and directories in the current path).

But what does this * wildcard do in the *.html pattern? It's like saying:

This part where the * is, there can be any number of characters in this spot. 0 characters, 1, 2, 3, even 100 characters. But after that, it all ends with .html.

So * is like a "joker card" of sorts, that means "anything can appear here".

Find File that Begins with this Name

And now that we know what the * wildcard does, we can find another use case for it. What if instead of the beginning, we place it at the end? Imagine something like scr*.

Let's run it and see:

find -name 'scr*' -type f

This command will find any file that begins with the name scr.

Find File that Ends with this Name

And we can do this in reverse, and find a file that ends with a certain name.

For example, to look for all files in the /usr/bin/ directory, that end with the name grep:

find /usr/bin/ -name '*grep' -type f

Find File that Contains this Name

Imagine we're looking for programs that have something to do with ZIP compression. And we know that in their file names they must have the word zip. Otherwise said: 

  • There can be any text before zip.
  • There can be any text after zip.

What's the "any card" that we know of? The * wildcard, of course. All we need to do is add it in two places now: Before "zip" and after "zip". So we get to: *zip*.

To look for any file that contains the word zip we can use a command like this:

find /usr/bin/ -name '*zip*' -type f

Sometimes, instead of searching for files that match some pattern, we might want to look for files that do not match that pattern.

For example, if we're looking for PNG image files, we'll do a search for any file that ends with .png.

But now imagine we're searching for anything except these images. And we don't want to be sitting there enumerating everything we want to find, like HTML files, CSS files, JavaScript files, and who knows what else. We just want to say: "Find me anything except files that match this pattern". Otherwise said: "Find all files that DO NOT match this pattern".

That's easy to do. We just add the -not operator before that search pattern. For example, if we want to find any file in the /home/alex/projects directory, that does NOT end with the .png extension, we can use a command like this:

find /home/alex/projects/ -type f -not -name '*.png'

And we'll get a result list like this:

All files that do not end with ".png".

If we'd remove the -not operator before our -name '*.png' search pattern, we'd get this instead:

We can negate any search pattern. So any search pattern we can think of, we just add -not before it, and we can find all files that do not match that pattern.

Make the Find Command Case Insensitive (Ignore Case of Letters)

There's a sort of unwritten rule on Linux: To have all file names written with all lowercase letters. Names like file instead of File or FILE. But, as with anything in life, we will sometimes encounter exceptions to this rule.

And, unlike Windows, Linux considers the three examples above entirely different files. On Windows we cannot create a file called file if we already have one called File. It would be considered the same name, because Windows does not care about letter case. For that operating system, file=File=FILE.

But, on Linux, here's me creating three files with these names:

And here they are, three separate files:

That's why the find command has a small "problem". If we tell it to find something named file, then it's very specific. It will find something with that exact name, in all lowercase letters, just as we wrote it:

find -name file

See? Just the first file was found. Because the other two files have different names. One begins with an uppercase "F", and the last one has all uppercase letters.

So how do we tell find to search for all files with this name, no matter the letter cases? Otherwise said, how do we make find case insensitive (ignore letter case)? Well, easily enough. We just use -iname instead of -name. Think of the i in there as "ignore case".

For example, to find all files with the name file, no matter what letters were used, uppercase, or lowercase, we can use this command:

find -iname file

And just like that, problem solved:

Now it found all three files.

Conclusion

find is a powerful command. It can search for files, and directories, based on almost any criteria we might think of. In this tutorial, we explored searching for files based on the names, or name patterns they might have. But find can also search according to how old a file is, its size, the permissions that are set for it, the owners it has, and so on.

We can run a command like this to read more about what the find command can do:

man find

This text manual can be scrolled through with the Page Up and Page Down keys. And we can exit the manual by pressing q.

If you're more of a visual learner, and you want to see advanced use cases of the find command, you can check out one of our Linux courses:

Linux Foundation Certified System Administrator (LFCS) | KodeKloud
Prepare for the Linux Foundation Certified System Administrator (LFCS) Exam

See you in the next blog!