TL;DR
Use xargs
, for example: echo "dest1 dest2" | xargs -n 1 cp src
Details
I am sure you are familiar with the cp
command: cp src dest
If we want to copy one file to multi destinations, we can use xargs
with the cp
command.
xargs
will take previous command's stdout as its following command's CLI parameter. Let's learn it with some examples:
1, Copy one file to multi files. Say we have "hello.txt" in our current folder, we want to make copy it as "hello1.txt" and "hello2.txt", we can do:
$ echo "hello1.txt hello2.txt" | xargs -n 1 cp hello.txt
$ ls
hello.txt hello1.txt hello2.txt
The -n 1
after xargs
means we want to take the output as cp
's CLI parameter one by one, so the above command is like:
$ cp hello.txt hello1.txt
$ cp hello.txt hello2.txt
2, Copy one file into several folders. Say if under the current folder, we have hello.txt
and 2 folders: folder1
and folder2
, and we want to copy hello.txt
to all subfolders (folder1 and folder2) under the current folder:
The first thing we need to do, is to use a command to list all subfolders. We have 2 ways to do this:
1) use ls -d
$ ls -d */
folder1/ folder2/
2) use find . -type d
$ find . -maxdepth 1 ! -path . -type d
./folder1
./folder2
Notice we use -maxdepth 1
here to skip sub-sub folders and use ! -path .
to skip current folder path "./"
Now we can combile this with xargs
command to copy the file to those folders:
$ ls -d */ | xargs -n 1 cp hello.txt
$ ls folder*
folder1:
hello.txt
folder2:
hello.txt
3, So far in our example, what xargs
does is appending the previous command's stdout to its following command's command parameter, but we can also inserting it to its following command's parameter with the -I
option.
For example, say if we want to delete hello.txt
under both folder1
and folder2
, we can do this:
$ ls -d */ | xargs -n 1 -I{} rm {}hello.txt
$ ls folder*
folder1:
folder2:
We can see the hello.txt
file is gone under those 2 folders. In this example, the ls -d */
will print folder1/
and folder2
, then with the -I
option in xargs, we kind of assign those stdout to a variable or a placeholder {}
, then concatenate the variable {} with hello.txt
, so essentially the above command is equal to:
rm folder1/hello.txt
rm folder2/hello.txt
Another way to do the multi deletion is, since rm
can take multiple parameter, as long as we find all hello.txt
under those folders, we can the simply use xargs
to pass it to rm
:
$ ls folder*/hello.txt | xargs rm
This is equal to:
$ rm folder1/hello.txt folder2/hello.txt
Or if we want to delete "hello.txt" under all folders:
$ find . -name hello.txt | xargs rm
Top comments (1)
Here's a variant of the same theme:
distribute.sh