There are errors in your assumptions, but first some background:
You should discern two uses of -exec
:
- with
\;
the {}
will be replaced by a single item found
- with
+
the {}
will be replaced by many items (as many as the commandline can hold).
Therefore your example of -exec
use invokes as many cp
command as items found by find
.
Using find ... -exec cmd {} ... +
is similar in efficiency as piping the output of find into a command that handles multiple input names.
You should also take into account that -exec
nicely handles filenames/paths with spaces, but when you pipe in the output from find to another program that can cause problems. Therefore some programs that expect a list of filenames from stdin can be given an option to have those filenames NUL separated (often -0
or --null
). And find
has and option to give them to the next program in that way by specifying: -print0
Now coming to your examples:
find . -type f -iname "*.cr2" | cp destination_directory
doesn't copy the files found, as cp doesn't read from standard input. You would have to use:
find . -type f -iname "*.cr2" | xargs cp -t destination_directory
or to handle the paths with spaces:
find . -type f -iname "*.cr2" -print0 | xargs -0 cp -t destination_directory
With about the same efficiency you could do:
find . -type f -iname "*.cr2" -exec cp -t destination_directory {} +
(As G-Man pointed out the {}
has to be at the end, before the +
)
All of the above do not build the hierarchy under the target directory for that and out of long habit even if the source directory is flat, I find myself using cpio
instead:
find . -type f -iname "*.cr2" -print0 | cpio -pdmv0 destination_directory
which nicely lists what it is doing along the way.
The relevant parts from man find
:
-exec command ;
Execute command; true if 0 status is returned. All following
arguments to find are taken to be arguments to the command
until an argument consisting of `;' is encountered. The string
`{}' is replaced by the current file name being processed
everywhere it occurs in the arguments to the command, not just
in arguments where it is alone, as in some versions of find.
Both of these constructions might need to be escaped (with a
`\') or quoted to protect them from expansion by the shell.
See the EXAMPLES section for examples of the use of the -exec
option. The specified command is run once for each matched
file. The command is executed in the starting directory.
There are unavoidable security problems surrounding use of the
-exec action; you should use the -execdir option instead.
-exec command {} +
This variant of the -exec action runs the specified command on
the selected files, but the command line is built by appending
each selected file name at the end; the total number of invoca‐
tions of the command will be much less than the number of
matched files. The command line is built in much the same way
that xargs builds its command lines. Only one instance of `{}'
is allowed within the command. The command is executed in the
starting directory.