The syntax is:
find ... -exec cmd {} +
find
will find a number of files based on the criteria in ...
and run cmd
with that list of file paths as arguments, as many as possible without surpassing the limit on the size of the arguments to a command.
If needed it may split the list of files and call cmd
several times. For instance, it may end up calling:
cmd ./file1 ./file2 ... ./file3000
cmd ./file3001 ./file3002 ... ./file4321
A limitation with that is that {}
has to be last. You can't for instance write:
find ... -exec cmd {} other args +
like you could with ';'
instead of '+'
.
You can write:
find ... -exec echo foo {} +
but not:
find ... -exec echo {} foo +
So, if you do need to add some extra arguments to cmd
after the list of files, you have to resort to calling a shell. (Other reasons why you'd need to call a shell would be any time you need to use a shell feature like redirections, pipes, some string expansions....)
In sh -c 'inline-script' x a b c
, for the inline-script
, $0
is x
, $1
is a
, $2
is b
... so "$@"
is the list of those 3 arguments: a, b and c. So in:
find ... -exec sh -c 'cmd "$@" other arg' find-sh {} +
For the inline script, $0
(which is used for instance when displaying error messages) is set to find-sh
and "$@"
is the list of files (what find
expands {}
to).
By using the exec
special builtin of the shell:
find ... -exec sh -c 'exec cmd "$@" other arg' find-sh {} +
We tell the shell not to fork an extra process to run cmd
, but instead to run it in the same process (replacing the running shell process with that command). Some shells like zsh
and some implementations of ksh
do that implicitly for the last command in an inline script (also bash
when there's only one command in the inline script like here).
-exec sh -c '(cmd1; cmd2;)' find-sh {} +
? – slm Oct 02 '13 at 19:13find-sh {}
are arguments to the sh -c '...' command, right? – slm Oct 02 '13 at 19:22find
will call/bin/sh
with as arguments("sh", "-c", "...", "find-sh", "./file1", "./file2"...). And inside
..., that maps (the shells maps that) to
$0being
"find-sh", and the positional parameters (
$1,
$2... which you could say are the arguments to the _inline script_) being
./file1,
./file2`. – Stéphane Chazelas Oct 02 '13 at 19:45