I would like to copy many files with the below command.

 cp `find /Volumes/DATA/ -name "*.app" -depth 1 2> /dev/null` /Volumes/VMWare/img/

But that doesn't work because if it finds a space then it interprets it as the end of the order.

How to fix this?


First, find can do something with its results; look at the -exec {} flag. You can do something like:

find /Volumes/DATA/ -name "*.app" -depth 1 2> /dev/null -exec cp '{}' /Volumes/VMWare/img/ \;

Notice the single quotes around the file placeholder "{}."

You could also use a pipe with xargs.

| improve this answer | |
  • The single quotes around {} won't do anything special. find already knows how to pass the argument without any shell doing splitting on the value. – Kusalananda Dec 3 '18 at 23:12
  • @Kusalananda I don't know, I've run into problems before and the man page shows it in the examples, e.g.: find . -type f -exec file '{}' \; – melds Dec 4 '18 at 2:49
  • It will only be an issue in non-sh shells, like csh and tcsh. I'm pointing this out specifically because you make it sound like adding the single quotes is important. It's not. – Kusalananda Dec 4 '18 at 6:14

In zsh, `...` like the modern form $(...) splits on characters of $IFS, which by default includes SPC, TAB, NL and NUL.

Of those, only NUL cannot occur in a file path, so you'd need:

cp $(find /Volumes/DATA/ -name "*.app" -depth 1 -print0 2> /dev/null) /Volumes/VMWare/img/

Or, instead of using the implicit word splitting done by $(...) using a global parameter, use an explicit splitting operator:

cp ${(0)"$(find /Volumes/DATA/ -name "*.app" -depth 1 -print0 2> /dev/null)"} /Volumes/VMWare/img/

But in any case, using find here has no benefit whatsoever over:

cp /Volumes/DATA/*.app(D) /Volumes/VMWare/img/

(here using the D glob qualifier so it also includes hidden files like find does, though it's likely you'd want to skip them anyway).

| improve this answer | |

Use -print0 with find to null terminate file names and feed this output to xargs with -0 to instruct xargs that file names from standard input are null terminated. And use -I to replace strings in the initial arguments.

find /Volumes/DATA/ -name '*.app' -maxdepth 1 -print0 | xargs -0 -I fn cp fn /Volumes/VMWare/img/

| improve this answer | |

Not the answer you're looking for? Browse other questions tagged or ask your own question.