find: Multiple Files

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

Menu