Sometimes you need to process files one of the time. But usually this is not necessary, and, it is faster to run a command on as many files as possible at a time, rather than once per file. Doing this saves on the time it takes to start up the command each time.
The -execdir and -exec actions have variants that build command lines containing as many matched files as possible.
This works as for -execdir command ;, except that the {} at the end of the command is expanded to a list of names of matching files. This expansion is done in such a way as to avoid exceeding the maximum command line length available on the system. Only one {} is allowed within the command, and it must appear at the end, immediately before the +. A + appearing in any position other than immediately after {} is not considered to be special (that is, it does not terminate the command).
This insecure variant of the -execdir action is specified by POSIX. The main difference is that the command is executed in the directory from which
find
was invoked, meaning that {} is expanded to a relative path starting with the name of one of the starting directories, rather than just the basename of the matched file.
Before find
exits, any partially-built command lines are
executed. This happens even if the exit was caused by the
-quit action. However, some types of error (for example not
being able to invoke stat()
on the current directory) can cause
an immediate fatal exit. In this situation, any partially-built
command lines will not be invoked (this prevents possible infinite
loops).
Another, but less secure, way to run a command on more than one file
at once, is to use the xargs
command, which is invoked like this:
xargs [option...] [command [initial-arguments]]
xargs
normally reads arguments from the standard input. These
arguments are delimited by blanks (which can be protected with double
or single quotes or a backslash) or newlines. It executes the
command (default is /bin/echo) one or more times with any
initial-arguments followed by arguments read from standard
input. Blank lines on the standard input are ignored.
Instead of blank-delimited names, it is safer to use find -print0
or find -fprint0 and process the output by giving the -0
or --null option to GNU xargs
, GNU tar
, GNU
cpio
, or perl
. The locate
command also has a
-0 or --null option which does the same thing.
You can use shell command substitution (backquotes) to process a list of arguments, like this:
grep -l sprintf `find $HOME -name '*.c' -print`
However, that method produces an error if the length of the .c
file names exceeds the operating system's command-line length limit.
xargs
avoids that problem by running the command as many times as
necessary without exceeding the limit:
find $HOME -name '*.c' -print | xargs grep -l sprintf
However, if the command needs to have its standard input be a terminal
(less
, for example), you have to use the shell command
substitution method or use the --arg-file option of
xargs
.
The xargs
command will process all its input, building command
lines and executing them, unless one of the commands exits with a
status of 255 (this will cause xargs to issue an error message and
stop) or it reads a line contains the end of file string specified
with the --eof option.