## 9.2. Delving Through a Deep Directory Tree

The first, most obvious, use of this utility is find's ability to locate old, big, or unused files whose locations you've forgotten. In particular, find's most fundamentally important characteristic is its ability to travel down subdirectories.

Normally the shell provides the argument list to a command. That is, Unix programs are frequently given filenames and not directory names. Only a few programs can be given a directory name and march down the directory searching for subdirectories. The programs find, tar (Section 38.3), du, and diff do this. Some versions of chmod (Section 50.5), chgrp, ls, rm, and cp will, but only if a -r or -R option is specified.

In general, most commands do not understand directory structures and rely on the shell to expand wildcards to directory names. That is, to delete all files whose names end with a `.o` in a group of directories, you could type:

>     % rm *.o */*.o */*/*.o

Not only is this tedious to type, it may not find all of the files you are searching for. The shell has certain blind spots. It will not match files in directories whose names start with a dot. And, if any files match `*/*/*/*.o`, they would not be deleted.

Another problem is typing the previous command and getting the error "Arguments too long." This means the shell would expand too many arguments from the wildcards you typed.

find is the answer to these problems.

A simple example of find is using it to print the names of all the files in the directory and all subdirectories. This is done with the simple command:

>     % find . -print

The first arguments to find are directory and file pathnames -- in the example, a dot (.) is one name for the current directory. The arguments after the pathnames always start with a minus sign (`-`) and tell find what to do once it finds a file; these are the search operators. In this case, the filename is printed.

You can use the tilde (`~`), as well as particular paths. For example:

>     % find ~ ~barnett /usr/local -print

And if you have a very slow day, you can type:

>     % find / -print

This command will list every file on the system. This is okay on single-user workstations with their own disks. However, it can tie up disks on multiuser systems enough to make users think of gruesome crimes! If you really need that list and your system has fast find or locate, try the command `find '/*'` or `locate ' *'` instead.

find sends its output to standard output, so once you've "found" a list of filenames, you can pass them to other commands. One way to use this is with command substitution:``

>     % ls -l `find . -print`

The find command is executed, and its output replaces the backquoted string. ls sees the output of find and doesn't even know find was used.

An alternate method uses the xargs command. xargs and find work together beautifully. xargs executes its arguments as commands and reads standard input to specify arguments to that command. xargs knows the maximum number of arguments each command line can handle and does not exceed that limit. While the command:

>     % ls -ld `find / -print`

might generate an error when the command line is too large, the equivalent command using xargs will never generate that error:

>     % find / -print | xargs ls -ld

--BB and JP

Copyright © 2003 O'Reilly & Associates. All rights reserved.