The sections that follow contain some extended examples that both give a good idea of the power of these programs, and show you how to solve common real-world problems.
To view a list of files that meet certain criteria, simply run your file viewing program with the file names as arguments. Shells substitute a command enclosed in backquotes with its output, so the whole command looks like this:
less `find /usr/include -name '*.h' | xargs grep -l mode_t`
You can edit those files by giving an editor name instead of a file viewing program.
You can pass a list of files produced by find
to a file archiving
program. GNU tar
and cpio
can both read lists of file
names from the standard input--either delimited by nulls (the safe way)
or by blanks (the lazy, risky default way). To use null-delimited
names, give them the `--null' option. You can store a file archive
in a file, write it on a tape, or send it over a network to extract on
another machine.
One common use of find
to archive files is to send a list of the
files in a directory tree to cpio
. Use `-depth' so if a
directory does not have write permission for its owner, its contents can
still be restored from the archive since the directory's permissions are
restored after its contents. Here is an example of doing this using
cpio
; you could use a more complex find
expression to
archive only certain files.
find . -depth -print0 | cpio --create --null --format=crc --file=/dev/nrst0
You could restore that archive using this command:
cpio --extract --null --make-dir --unconditional \ --preserve --file=/dev/nrst0
Here are the commands to do the same things using tar
:
find . -depth -print0 | tar --create --null --files-from=- --file=/dev/nrst0 tar --extract --null --preserve-perm --same-owner \ --file=/dev/nrst0
Here is an example of copying a directory from one machine to another:
find . -depth -print0 | cpio -0o -Hnewc | rsh other-machine "cd `pwd` && cpio -i0dum"
This section gives examples of removing unwanted files in various situations. Here is a command to remove the CVS backup files created when an update requires a merge:
find . -name '.#*' -print0 | xargs -0r rm -f
You can run this command to clean out your clutter in `/tmp'. You might place it in the file your shell runs when you log out (`.bash_logout', `.logout', or `.zlogout', depending on which shell you use).
find /tmp -user $LOGNAME -type f -print0 | xargs -0 -r rm -f
To remove old Emacs backup and auto-save files, you can use a command like the following. It is especially important in this case to use null-terminated file names because Emacs packages like the VM mailer often create temporary file names with spaces in them, like `#reply to David J. MacKenzie<1>#'.
find ~ \( -name '*~' -o -name '#*#' \) -print0 | xargs --no-run-if-empty --null rm -vf
Removing old files from `/tmp' is commonly done from cron
:
find /tmp /var/tmp -not -type d -mtime +3 -print0 | xargs --null --no-run-if-empty rm -f find /tmp /var/tmp -depth -mindepth 1 -type d -empty -print0 | xargs --null --no-run-if-empty rmdir
The second find
command above uses `-depth' so it cleans out
empty directories depth-first, hoping that the parents become empty and
can be removed too. It uses `-mindepth' to avoid removing
`/tmp' itself if it becomes totally empty.
find
can help you remove or rename a file with strange characters
in its name. People are sometimes stymied by files whose names contain
characters such as spaces, tabs, control characters, or characters with
the high bit set. The simplest way to remove such files is:
rm -i some*pattern*that*matches*the*problem*file
rm
asks you whether to remove each file matching the given
pattern. If you are using an old shell, this approach might not work if
the file name contains a character with the high bit set; the shell may
strip it off. A more reliable way is:
find . -maxdepth 1 tests -ok rm '{}' \;
where tests uniquely identify the file. The `-maxdepth 1'
option prevents find
from wasting time searching for the file in
any subdirectories; if there are no subdirectories, you may omit it. A
good way to uniquely identify the problem file is to figure out its
inode number; use
ls -i
Suppose you have a file whose name contains control characters, and you have found that its inode number is 12345. This command prompts you for whether to remove it:
find . -maxdepth 1 -inum 12345 -ok rm -f '{}' \;
If you don't want to be asked, perhaps because the file name may contain a strange character sequence that will mess up your screen when printed, then use `-exec' instead of `-ok'.
If you want to rename the file instead, you can use mv
instead of
rm
:
find . -maxdepth 1 -inum 12345 -ok mv '{}' new-file-name \;
Suppose you want to make sure that everyone can write to the directories in a certain directory tree. Here is a way to find directories lacking either user or group write permission (or both), and fix their permissions:
find . -type d -not -perm -ug=w | xargs chmod ug+w
You could also reverse the operations, if you want to make sure that directories do not have world write permission.
If you want to classify a set of files into several groups based on different criteria, you can use the comma operator to perform multiple independent tests on the files. Here is an example:
find / -type d \( -perm -o=w -fprint allwrite , \ -perm -o=x -fprint allexec \) echo "Directories that can be written to by everyone:" cat allwrite echo "" echo "Directories with search permissions for everyone:" cat allexec
find
has only to make one scan through the directory tree (which
is one of the most time consuming parts of its work).