The only standard way to use find -exec …
is to pass {}
as a separate argument. The behavior when an argument contains {}
is not standardized. It seems that you're used to the GNU behavior where {}
is substituted in a substring. The find
command on Solaris only substitutes {}
when an argument consists only of {}
.
The GNU behavior is not particularly useful, and sometimes annoying, because substituting a file name inside an argument is brittle. Unless you have known constraints on the file names, there's no way to know where a file name starts and ends. For example, with GNU find, find / -exec sh -c "echo {}" \;
does not print the file names in general. It only prints the file names when they don't contain any shell special character. If you run it in a directory containing a file called ;rm -r ~
, say goodbye to your files.
The reliable (and portable) way to call a shell from find -exec
is to pass the file names as an argument to the shell.
find … -exec sh -c 'echo "$0"' {} \;
In most cases you can pass arguments in batches and iterate over the arguments in the shell. It's somewhat faster. Note that the very first argument after the shell code is $0
which is not includes in "$@"
.
find … -exec sh -c 'for x; do echo "$x"; done' _ {} +
See also Why does my shell script choke on whitespace or other special characters?