Introduction to the Command Line

Searching for Files

When you first get a computer, you tend to place files in just a couple folders or directories. But as your list of files grows, you have to create some subdirectories and spread the files around in order to keep your sanity. Eventually, you forget where files are. "Where did I store those photos I took in Normandy?"

You could run ls -R, as in the following section, and start running your finger down the screen, but why? Computers are supposed to be about automation. Let the computer figure out where the file is.

If you know your file is named "somefile", telling the computer what to do is pretty easy.

$ find . -name somefile -print 
./files/somefile

The find command takes more arguments than the other commands we've seen so far, but if you use it for a while you'll find it becomes natural.  Its first argument (the '.') tells find where to start looking: the directory at the top of everything you're searching through. In this case, we're telling find to start looking in whatever directory we're in right now.

The -name argument tells it to look for a file named somefile.  Finally, the -print option tells the command to print out on our screen the location of any file that matches the name it was given.

Wildcards with Find

What if you don't remember the name of the file you're looking for?  You might only remember that it starts with "some".  Luckily, find can handle that too. 

$ find . -name 'some*' -print 
./dir1/subdir2/files/somefile_other
./some_other_file
./files/somefile 

This time it found a few more files than you were after but it still found the one you wanted.  As you can see, the find command can process wildcards in much the same way the shell can.  Here you asked it to look for anything that starts with the letters "some".

The "*", "?", and "[ ]" wildcards can all be used just as they would be in the shell.  However, since find is using the wildcards you have to make sure they remain unaltered by the shell.  To do this you can surround the name you're searching for, and the wildcards it contains, in single quotes.

Trimming The Search Path

With just a name and a location, find will begin searching through every directory below its starting point, looking for matches.  Depending on how many subdirectories you have where you're searching, find can take a lot of time to look in places you know don't contain the file.

It is possible, however, to control how far find sinks in the directory tree.

$ find . -maxdepth 1 -name 'some*' -print 
./some_other_file

By using the -maxdepth argument we can tell find to go no lower than the number of directories we specify.  A maxdepth of 1 says: don't leave the starting directory. A maxdepth of 3 would allow find to descend 3 directories from where it started, and so on.  It's important to note that -maxdepth should immediately follow the start location, or find will complain.

Using Criteria

The find command can search for files based on any criteria the filesystem know about files. For instance, you can search for files based on:

  • When they were last modified or accessed (somebody read them)
  • How big they are
  • Who owns them, or what group they are in
  • What permissions (read, write, execute) they have
  • What type of file (directory, regular file) they are

and other criteria described in the manual page. Here we'll just show a couple popular options.

The -mtime option shows the latest modification time. Suppose you just can't remember anything about a file's name, but know that you created or modified it within the past three days. You can find all the files in your home directory that were created or modified within the past three days through:

$ find ~ -mtime -3 -print

Notice the minus sign before the 3, for "less than." If you know you created the file yesterday (between 24 and 48 hours ago), you can search for an exact day:

$ find ~ -mtime 1 -print

 To find files that are more than 30 days old (caution: there will be a lot of these), use a plus sign:

$ find ~ -mtime +30 -print

Perhaps you want to remove old files that are large, before backing up a directory. Combine -mtime with -size to find these files. The file has to match all the criteria you specify in order to be printed.

$ find directory_to_backup  -mtime +30  -size +500k  -print

We've specified +500k as our -size option. The plus sign means "greater than" and "500k" means "500 kilobytes in size".

Using Find To Run a Command on Multiple Files

The find command can do much more powerful things than print filenames. You can combine it with any other command you want, so that you can remove files, move them around, look for text in them, and so on. On those occasions, the find command with its -exec option is just what you'll need.

Because the next example is long, it is divided onto two lines, with a backslash at the end of the first so the shell keeps reading and keeps the two lines as one command. The first line is the same as the command to find old, large files in the previous section.

$ find directory_to_backup  -mtime +30  -size +500k -print \
              -exec rm {} \;

The -exec option is followed by an rm command, but there are two odd items after it:

  • {} is a special convention in the -exec option that means "the current file that was found"
  • \; is necessary to tell find what the end of the command is. A command can have any number of arguments. Think of -exec and \; as surrounding the command you want to execute.

So we find each file, print the name through -print (which we don't have to do, but we're curious to see what's being removed), and then remove it in the -exec option.

Clearly, a tiny mistake in a find command could lead to major losses of data when used with -exec. Test your commands on throw-away files first!

Using cp you can see how the bracket pairs can be specified multiple times, allowing the file's name to be easily duplicated.

$ find . -name 'file*' -exec cp {} {}.backup \;  

Experiment and practice!