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?
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.
Get all sub-directories names through ls
and save them to some temporary file say, allFolders.txt
ls > allFolders.txt
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.
Get all sub-directories names through ls
and save them to some temporary file say, allFolders.txt
ls > allFolders.txt
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.
Source: Stackoverflow.com