You're almost there. You need to run a separate cp
command for each destination directory, because cp
only makes one copy of every source file. The primary purpose of xargs
is to run one command over multiple arguments, but you can tell it to pass a single item at a time with the -n
option. Also {} ;
is the syntax of find … -exec
; you don't need (and can't use) it with xargs
.
echo dir{1..3} | xargs -n 1 cp file{1..5}
Note that this only works if your directory names do not contain any whitespace or any of the characters \'"
, because xargs
has no way to tell that those characters are part of file names and not quoting and separating input files. An alternative method that doesn't have any such problem is to use a shell loop:
for d in dirs{1..3}; do
cp file{1..5} "$d"
done
All this assumes that you can easily distinguish between files and directories by their names. If you can't, you can match directories by adding a /
at the end; for example */
matches all directories in the current directories, foo[0-9]*/
matches all directories whose name begins with foo
and a digit, etc. There is no similar way to match only non-directories in most shells, but if you pass directories to cp
with no argument to tell it to make a recursive copy, the directories are ignored with an error message.
for d in */; do
cp * "$d"
done
In zsh, you can use glob qualifiers to match only certain file types.
for d in *(/); do
cp *(.) $d
done
for x in dir*; do cp file* $x; done
with GNUbash
)).