[Often, when you find a file, you don't just want to see its name; you want to do something, like grep for a text string. To do this, use the -exec operator. This allows you to specify a command that is executed upon each file that is found. -TOR ]
The syntax is peculiar and in many cases, it is simpler just to pipe the output of find to xargs (17.2). However, there are cases where -exec is just the thing, so let's plunge in and explain its peculiarities.
The -exec operator allows you to execute any command, including another find command. If you consider that for a moment, you realize that find needs some way to distinguish the command it's executing from its own arguments. The obvious choice is to use the same end-of-command character as the shell (i.e., the semicolon). Since the shell uses the semicolon (8.5) itself, it is necessary to escape the character with a backslash or quotes.
Therefore, every -exec operator ends with the characters \;
.
There is one more special argument that
find
treats differently:
{}
.
These two characters are used as the variable whose name is the file
find
found.
Don't bother rereading that last line.
An example will clarify the usage.
The following is a trivial case, and uses the
-exec
operator with
echo (8.6)
to mimic the
-print
operator:
%find . -exec echo {} \;
The C shell
uses the characters
{
and }
(9.5),
but doesn't change
{}
together,
which is why it is not necessary to quote these characters.
The semicolon must be quoted, however.
Quotes can be used instead of a backslash:
%find . -exec echo {} ';'
as both will sneak the semicolon past the shell and get it to the find command. As I said before, find can even call find. If you wanted to list every symbolic link in every directory owned by a group staff, you could execute:
`...` |
% |
---|
To search for all files with group-write permission and remove the permission, you can use:
-perm |
% |
---|
or:
%find . -perm -20 -print | xargs chmod g-w
The difference between -exec and xargs is subtle. The first one will execute the program once per file, while xargs can handle several files with each process. However, xargs may have problems (9.22) with filenames that contain embedded spaces.
Occasionally people create a strange file that they can't delete. This could be caused by accidentally creating a file with a space or some control character in the name. find and -exec can delete this file, while xargs could not. In this case, use ls -il to list the files and i-numbers (1.22), and use the -inum operator with -exec (23.16) to delete the file:
%find . -inum 31246 -exec rm {} ';'
If you wish, you can use
-ok
which does the same as
-exec,
except the program asks you first to confirm the action
before executing the command.
It is a good idea to be cautious when using
find,
because the program can make a mistake into a disaster.
When in doubt, use
echo
as the command.
Or send the output to a file and examine the file
before using the file as input to
xargs.
This is how I discovered that
find
requires
{}
to stand alone
in the arguments to
-exec.
I wanted to rename some files using
-exec mv {} {}.orig
but find wouldn't replace the {}
in {}.orig
.
I learned that I have to
write a shell script (17.11)
that I tell
find
to execute.
[A little Bourne shell
while loop (44.10)
with
redirected input (45.23)
can handle that too:
> | $ |
---|
find writes the filenames to its standard output.
The while loop and its
read command (44.13)
read the filenames from standard input, then make them
available as $file
, one by one. -JP ]
Articles 17.12 and 17.24 have more examples of -exec.
-