[linux] How to copy a file to multiple directories using the gnu cp command

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?

This question is related to linux bash shell

The answer is


Wildcards also work with Roberts code

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

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


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}


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

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

ls -d */ | xargs -iA cp file.txt A

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.


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


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).


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.


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).


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.


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.


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


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).


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


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.


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.


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.


These answers all seem more complicated than the obvious:

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

If you want to do it without a forked command:

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


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.


These answers all seem more complicated than the obvious:

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

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

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

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.


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
    

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}


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.


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

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

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.


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.


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


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.


Wildcards also work with Roberts code

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

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.


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).


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
    

ls -d */ | xargs -iA cp file.txt A

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


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.


Examples related to linux

grep's at sign caught as whitespace How to prevent Google Colab from disconnecting? "E: Unable to locate package python-pip" on Ubuntu 18.04 How to upgrade Python version to 3.7? Install Qt on Ubuntu Get first line of a shell command's output Cannot connect to the Docker daemon at unix:/var/run/docker.sock. Is the docker daemon running? Run bash command on jenkins pipeline How to uninstall an older PHP version from centOS7 How to update-alternatives to Python 3 without breaking apt?

Examples related to bash

Comparing a variable with a string python not working when redirecting from bash script Zipping a file in bash fails How do I prevent Conda from activating the base environment by default? Get first line of a shell command's output Fixing a systemd service 203/EXEC failure (no such file or directory) /bin/sh: apt-get: not found VSCode Change Default Terminal Run bash command on jenkins pipeline How to check if the docker engine and a docker container are running? How to switch Python versions in Terminal?

Examples related to shell

Comparing a variable with a string python not working when redirecting from bash script Get first line of a shell command's output How to run shell script file using nodejs? Run bash command on jenkins pipeline Way to create multiline comments in Bash? How to do multiline shell script in Ansible How to check if a file exists in a shell script How to check if an environment variable exists and get its value? Curl to return http status code along with the response docker entrypoint running bash script gets "permission denied"