I’ve been working with find -exec and find | xargs for the past few hours exploring and experimenting, and now I’ve found a variation of the command that I haven’t seen anywhere else.
For example this find command to get all files in the child subdirectories and copy them to the current directory
find . -type f -regex './[^.].*/[^.*].*' -exec sh -c 'cp "$@" .' thiscanbeanything {} +
will all execute on one line like so:
cp ./testy/bar ./testy/baz ./testy/foo .
Instead of the usual:
find . -type f -regex './[^.].*/[^.*].*' -exec sh -c 'cp {} .' ;
which executes on multiple lines
cp ./testy/bar . cp ./testy/baz . cp ./testy/foo .
Moreover in the first command the output will be only:
cp ./testy/baz ./testy/foo .
Unless the sh -c 'cmd'
is followed by something else, which in my example was thiscanbeanything.
Could someone elucidate what’s going on, or if this is even viable?
Advertisement
Answer
To understand what is going on, have a look at this:
$ sh -c 'echo 0=$0 1=$1 2=$2' thiscanbeanything one two 0=thiscanbeanything 1=one 2=two
This executes sh
with the option -c 'echo 0=$0 1=$1 2=$2'
and three arguments thiscanbeanything one two
.
Normally, $0
is the name of the script being executed. When running sh -c
, there is no script but the name is taken from the first argument that your provide which, in this case, is thiscanbeanything
.
Documentation
This behavior is documented in man bash
under the -c
option:
-c string
If the -c option is present, then commands are read from string. If there are arguments after the string, they are assigned to the positional parameters, starting with $0.