223

Is it possible to copy a single file to multiple directories using the cp command ?

I tried the following, which did not work:

cp file1 /foo/ /bar/
cp file1 {/foo/,/bar}

I know it's possible using a for loop, or find. But is it possible using the gnu cp command?

1
  • This site is for programming questions. Try asking this question on superuser.com Commented May 9 at 0:35

23 Answers 23

609

You can't do this with cp alone but you can combine cp with xargs:

echo dir1 dir2 dir3 | xargs -n 1 cp file1

Will copy file1 to dir1, dir2, and dir3. xargs will call cp 3 times to do this, see the man page for xargs for details.

Sign up to request clarification or add additional context in comments.

12 Comments

More information on xargs: cyberciti.biz/faq/…
@Simon how so? "You can't do this with cp alone" Just because the answer attempted to be helpful by suggesting another way does not mean the question was not answered.
@NickC The asker specified : "I know it's possible using a for loop, or find. But is it possible using the gnu cp command?" The good answer is the one accepted.
Stipulating that answers be accepted based on whether they technically answer the question would be insufferably pedantic and not really useful.
Very helpful! For other beginners like me: you can't use regex with cp, but you can in first part of this command (e.g. echo dir[1-3] | xargs -n 1 cp filename).
|
113

No, cp can copy multiple sources but will only copy to a single destination. You need to arrange to invoke cp multiple times - once per destination - for what you want to do; using, as you say, a loop or some other tool.

6 Comments

Thanks for the answer! Now that I think about it a bit more, without extra flags (which do not exist) cp will not know what is the source and what is the DEST dir.
This is not the correct answer. Please see Robert Gamble's answer.
@Nocturne: which part of what I said is incorrect? Robert gives an example of using another tool to invoke cp multiple times as I suggest. There are many possible solutions that involve using other tools or constructs to do that, but the OP did indicate he was already aware that is possible.
Sad, it would be great for cp (and scp) to support that feature. Yet we can use tee to do the split. superuser.com/questions/32630/…
@moonshadow: Of course your answer is correct. I think PlagueHammer wants to say that in this context the other answer is more useful. Perhaps you may include something like that in your answer too?
|
80

Wildcards also work with Roberts code

echo ./fs*/* | xargs -n 1 cp test 

2 Comments

and the whole comment... For example, to move a root-owned file (a symlink actually) that was on my desktop to all users desktop I first had to sudo su (didn't work otherwise) then used: echo /home/*/Desktop/ | xargs -n 1 cp -av /home/myusername/Desktop/file.
macOS 11 Big Sur: Works fine! Used it to quickly propagate Finder folder view settings which live in a .DS_Store file from my source folder to all sibling folders. echo ../* | xargs -n 1 cp .DS_Store worked fine. Copied to all destinations except to itself luckily. cp: ../my-current-folder/.DS_Store and .DS_Store are identical (not copied).' In a first test run I did it with test.txt which I then easily batch removed with rm ../*/test.txt. Coping the .DS_Store file worked too. P.S.: Sadly the Finder folder view customization didn't propagate. But that's another issue.
20

I would use cat and tee based on the answers I saw at https://superuser.com/questions/32630/parallel-file-copy-from-single-source-to-multiple-targets instead of cp.

For example:

cat inputfile | tee outfile1 outfile2 > /dev/null

3 Comments

A cursory test I just ran shows this to be the best performer if your destinations are different physical drives (keeping two physical copies of a file base like source video for a digital film).
If you're using bash 3.0 or higher, you can use ranges as follows: cat <inputfile> | tee /path-to-files/outfile{1..4} > /dev/null
tee < inputfile outfile1 outfile2 > /dev/null is also a useful pattern as shown by Taywee's answer. Note the use of io-redirection with '<' so that piping from cat is not needed.
18

As far as I can see it you can use the following:

ls | xargs -n 1 cp -i file.dat

The -i option of cp command means that you will be asked whether to overwrite a file in the current directory with the file.dat. Though it is not a completely automatic solution it worked out for me.

5 Comments

While it is good to have added the -i guard, won't that prompt you about over writing every file? rather than copying to the directories?
@Hedgehog Well, I think that this command is useful when there is a file in the directory and one wants to copy it to subdirectories of the directory. In this case a file can be overwritten only once. Thanks for your question!
For me, it printed a series of cp: overwrite questions, but I didn't have to answer any of them, and it didn't overwrite the files.
Also printed a series of questions + copied to file with name of dir with ':' character at the end, no working solution at all, Paul's solution is working perfectly
ls | xargs is innately unsafe; it'll fail badly with filenames with spaces, f/e. Filenames with literal quotation characters, backslashes, etc. can also mess things up.
14

These answers all seem more complicated than the obvious:

for i in /foo /bar; do cp "$file1" "$i"; done

3 Comments

an elegant and working, to do it for all directories in the current dir, one can use for d in */ ; do cp $file "$i" done
@FantomX1 I think you have a typo. Shouldn't it be: for i in */ ; do cp $file "$i" done? But thanks to both of you.
@Torsten Yeah, I tested it, I had there a typo as you said, thanks for correcting
9

ls -db di*/subdir | xargs -n 1 cp File

-b in case there is a space in directory name otherwise it will be broken as a different item by xargs, had this problem with the echo version

Comments

7

Not using cp per se, but...

This came up for me in the context of copying lots of Gopro footage off of a (slow) SD card to three (slow) USB drives. I wanted to read the data only once, because it took forever. And I wanted it recursive.

$ tar cf - src | tee >( cd dest1 ; tar xf - ) >( cd dest2 ; tar xf - ) | ( cd dest3 ; tar xf - )

(And you can add more of those >() sections if you want more outputs.)

I haven't benchmarked that, but it's definitely a lot faster than cp-in-a-loop (or a bunch of parallel cp invocations).

Comments

6

If you want to do it without a forked command:

tee <inputfile file2 file3 file4 ... >/dev/null

Comments

5

To use copying with xargs to directories using wildcards on Mac OS, the only solution that worked for me with spaces in the directory name is:

find ./fs*/* -type d -print0 | xargs -0 -n 1 cp test 

Where test is the file to copy
And ./fs*/* the directories to copy to

The problem is that xargs sees spaces as a new argument, the solutions to change the delimiter character using -d or -E is unfortunately not properly working on Mac OS.

Comments

3

Essentially equivalent to the xargs answer, but in case you want parallel execution:

parallel -q cp file1 ::: /foo/ /bar/

So, for example, to copy file1 into all subdirectories of current folder (including recursion):

parallel -q cp file1 ::: `find -mindepth 1 -type d`

N.B.: This probably only conveys any noticeable speed gains for very specific use cases, e.g. if each target directory is a distinct disk.

It is also functionally similar to the '-P' argument for xargs.

Comments

0

No - you cannot.

I've found on multiple occasions that I could use this functionality so I've made my own tool to do this for me.

http://github.com/ddavison/branch

pretty simple -
branch myfile dir1 dir2 dir3

1 Comment

There are often scenarios where I would write my own such script, but I tend to use so many machines nowadays that keeping them all in sync seems like a major hassle. If only there was a way to mount a cloud web directory to /e for example, just once on each machine, then I could write my own powertools and keep them forever.
0
ls -d */ | xargs -iA cp file.txt A

2 Comments

How about a bit of explanation?
This actually works, but an explanation would have been great
0

Suppose you want to copy fileName.txt to all sub-directories within present working directory.

  1. Get all sub-directories names through ls and save them to some temporary file say, allFolders.txt

    ls > allFolders.txt
    
  2. Print the list and pass it to command xargs.

    cat allFolders.txt | xargs -n 1 cp fileName.txt
    

Comments

0

Another way is to use cat and tee as follows:

cat <source file> | tee <destination file 1> | tee <destination file 2> [...] > <last destination file>

I think this would be pretty inefficient though, since the job would be split among several processes (one per destination) and the hard drive would be writing several files at once over different parts of the platter. However if you wanted to write a file out to several different drives, this method would probably be pretty efficient (as all copies could happen concurrently).

Comments

0

Using a bash script

DESTINATIONPATH[0]="xxx/yyy"
DESTINATIONPATH[1]="aaa/bbb"
                ..
DESTINATIONPATH[5]="MainLine/USER"
NumberOfDestinations=6

for (( i=0; i<NumberOfDestinations; i++))
    do
        cp  SourcePath/fileName.ext ${DESTINATIONPATH[$i]}

    done
exit

1 Comment

I gave this a downvote. The question specifically asked for a non-loop solution.
0

The shortest & easiest way to copy a file to multiple directories using gnu cp command:

$ ls -db *folders*|xargs -n1 cp -v *files*


Explanation of the commands:
ls -db keeps white space intact when piping & prints every directory that matches the name: [*folders*]
| takes standard output from everything to the left & pipes it into standard input of everything to the right
xargs -n1 iterates once over the list of each printed directory matched
cp -v makes a verbose copy (for easy verification) of every file that matches the name: [*files*]

2 Comments

You should explain how this code works. What is -db for? -n1, -v? How is it better than the other 21 answers?
Edited first sentence to make solution clearer & wrote an explanation of the command line.
-1

if you want to copy multiple folders to multiple folders one can do something like this:

echo dir1 dir2 dir3 | xargs -n 1 cp -r /path/toyourdir/{subdir1,subdir2,subdir3}

Comments

-1

If all your target directories match a path expression — like they're all subdirectories of path/to — then just use find in combination with cp like this:

find ./path/to/* -type d -exec cp [file name] {} \;

That's it.

2 Comments

I gave this a downvote. The question specifically asked for a non-find solution.
Thanks you for being so thorough @AlexTelon. I guess I missed that bit. I hope you were consistent as well and gave a down-vote to every other answer using find in thread.
-2

If you need to be specific on into which folders to copy the file you can combine find with one or more greps. For example to replace any occurences of favicon.ico in any subfolder you can use:

find . | grep favicon\.ico | xargs -n 1 cp -f /root/favicon.ico

Comments

-3

This will copy to the immediate sub-directories, if you want to go deeper, adjust the -maxdepth parameter.

find . -mindepth 1 -maxdepth 1 -type d| xargs -n 1 cp -i index.html

If you don't want to copy to all directories, hopefully you can filter the directories you are not interested in. Example copying to all folders starting with a

find . -mindepth 1 -maxdepth 1 -type d| grep \/a |xargs -n 1 cp -i index.html

If copying to a arbitrary/disjoint set of directories you'll need Robert Gamble's suggestion.

Comments

-3

I like to copy a file into multiple directories as such: cp file1 /foo/; cp file1 /bar/; cp file1 /foo2/; cp file1 /bar2/ And copying a directory into other directories: cp -r dir1/ /foo/; cp -r dir1/ /bar/; cp -r dir1/ /foo2/; cp -r dir1/ /bar2/

I know it's like issuing several commands, but it works well for me when I want to type 1 line and walk away for a while.

1 Comment

You are answering a 6 year old question with 15 other answers. Your answer needs to be pretty novel. My opinion - it is not.
-4

For example if you are in the parent directory of you destination folders you can do:

for i in $(ls); do cp sourcefile $i; done

2 Comments

The question says it's possible with a for loop, so this really doesn't add anything.
Downvoted. Never try to parse the output of ls, and always quote variables. for i in ./*; do cp sourcefile "$i"; done

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.