How to force 'cp' to overwrite directory instead of creating another one inside?
Solution 1
You can do this using -T
option in cp
.
See Man page for cp
.
-T, --no-target-directory
treat DEST as a normal file
So as per your example, following is the file structure.
$ tree test
test
|-- bar
| |-- a
| `-- b
`-- foo
|-- a
`-- b
2 directories, 4 files
You can see the clear difference when you use -v
for Verbose.
When you use just -R
option.
$ cp -Rv foo/ bar/
`foo/' -> `bar/foo'
`foo/b' -> `bar/foo/b'
`foo/a' -> `bar/foo/a'
$ tree
|-- bar
| |-- a
| |-- b
| `-- foo
| |-- a
| `-- b
`-- foo
|-- a
`-- b
3 directories, 6 files
When you use the option -T
it overwrites the contents, treating the destination like a normal file and not directory.
$ cp -TRv foo/ bar/
`foo/b' -> `bar/b'
`foo/a' -> `bar/a'
$ tree
|-- bar
| |-- a
| `-- b
`-- foo
|-- a
`-- b
2 directories, 4 files
This should solve your problem.
Solution 2
If you want to ensure bar/
ends up identical to foo/
, use rsync
instead:
rsync -a --delete foo/ bar/
If just a few things have changed, this will execute much faster than removing and re-copying the whole directory.
-a
is 'archive mode', which copies faithfully files infoo/
tobar/
--delete
removes extra files not infoo/
frombar/
as well, ensuringbar/
ends up identical- If you want to see what it's doing, add
-vh
for verbose and human-readable - Note: the slash after
foo
is required, otherwisersync
will copyfoo/
tobar/foo/
rather than overwritingbar/
itself.- (Slashes after directories in rsync are confusing; if you're interested, here's the scoop. They tell rsync to refer to the contents of the directory, rather than the directory itself. So to overwrite from the contents of
foo/
onto the contents ofbar/
, we use a slash on both. It's confusing because it won't work as expected with a slash on neither, though; rsync sneakily always interprets the destination path as though it has a slash, even though it honors an absence of a slash on the source path. So we need a slash on the source path to make it match the auto-added slash on the destination path, if we want to copy the contents offoo/
intobar/
, rather than the directoryfoo/
itself landing intobar/
asbar/foo
.)
- (Slashes after directories in rsync are confusing; if you're interested, here's the scoop. They tell rsync to refer to the contents of the directory, rather than the directory itself. So to overwrite from the contents of
rsync
is very powerful and useful, if you're curious look around for what else it can do (such as copying over ssh).
Solution 3
Do it in two steps.
rm -r bar/
cp -r foo/ bar/
Solution 4
Use this cp
command:
cp -Rf foo/* bar/
Solution 5
The following command ensures dotfiles (hidden files) are included in the copy:
$ cp -Rf foo/. bar
Related videos on Youtube
saketrp
Updated on July 08, 2022Comments
-
saketrp almost 2 years
I'm trying to write a Bash script that will overwrite an existing directory. I have a directory
foo/
and I am trying to overwritebar/
with it. But when I do this:cp -Rf foo/ bar/
a new
bar/foo/
directory is created. I don't want that. There are two files infoo/
;a
andb
. There are files with same names inbar/
as well. I want thefoo/a
andfoo/b
to replacebar/a
andbar/b
. -
Ara about 9 yearsThis doesn't remove files that are present in bar but not in foo.
-
anubhava about 9 yearsDon't know what you mean by that. Why should
cp
command be removing file from source? -
Ara about 9 yearsMy understanding was that when you 'overwrite an existing directory' with another one, at the end the overwritten directory should be a copy of the other one. I.e. at the end bar should be a copy of foo, as it is the case with @jonathan-wheeler answer but if you had a file bar/c and no foo/c then bar/c doesn't get deleted. On a side note, I've just noticed that it's not the case with Saurabh Meshram's answer either.
-
Ara about 9 yearsMaybe we don't agree on what overwrite means, for me it's basically replace, while you might meant megre ? It's hard to tell what OP wants exactly because she only mentionned 2 files that are both in foo and bar.
-
dnfehren over 8 yearsjust in case anyone is tripped up by this it won't work with OSX cp developer.apple.com/library/mac/documentation/Darwin/Reference/…
-
Mateng over 7 yearsIs this true? Looks unusual.
-
robo over 7 yearsIt's not clear that this answer is what the OP is looking for, although the examples given above mask the problem... With the -T option, files that are in an existing target (
bar/
) but not in the source (foo/
) will be left in place, so this is not what most people would consider a complete overwrite of the directory. ie. ifbar/baz
existed already, it would still exist afterwards... -
robo over 7 yearsThis is actually the only example given so far that will ensure that
bar
is identical in content tofoo
, not a combination of items fromfoo
plus other items that may have already existed inbar
. The highly upvoted answer from @Saurabh Meshram below has this problem. -
Elia Grady almost 7 yearsBe extra careful using this, as it will remove all files from bar, even hidden ones.
-
Matmarbon almost 7 years@Mateng I just tested it - yes it is true.
-
JohnyTex over 6 yearsIs there no option to clean target folder in the process? I can't believe it!
-
Michael Dimmitt over 6 yearsmac osx:
rm -rf bar/; cp -r foo/ !$
-
theferrit32 over 6 yearsThis answer does answer the op question, but doesn't address the case of if the destination already exists and you want to remove contents it contains but the source directory does not. This is not an expected behavior of copying files from one place to the other. It only overwrites in the target things that are also in the source, it doesn't touch anything in the target that is not in the source. You can clean the target folder by prepending a command to do it:
rm -rf bar/* && cp -TRv foo/ bar/
-
Lucas over 6 yearsThe tip about the !$ is awesome!
-
Jaspreet Singh almost 6 years
.
means all the files in the directory. So, naturally the hidden files would be included. -
tongueroo over 5 yearsLike this answer better than the
cp -T
option because it also works on macosx 👍 -
Assimilater over 5 yearsThis isn't always viable...or desired...imagine if
foo
andbar
are large directories...maybe there are files inbar
that are not infoo
that you don't want to remove. This shouldn't be considered a realistic answer imho -
Assimilater over 5 yearsI'm not a mind reader...I don't see further clarification what the OP was looking for, but this was DEFINITELY the answer that I (MEEEE) was looking for
-
Sulphur over 4 yearsjust in case anyone is tripped up by why the link in the most upvoted comment is not working, here it is: web.archive.org/web/20170909193852/https://developer.apple.com/…
-
Nitwit about 4 yearsAlthough worked for me, but not the best solution since there might be file included in foo/ but not in bar/ which will be deleted after doing this.
-
qwr almost 4 years@robo and also the rsync answer now
-
xpusostomos almost 4 years-T is a gnuism. I believe the BSDism is to put a slash / after the src directory. I'm not sure where MacOS gets its convention or what the relevant standards have to say, but it seems to follow BSD here.
-
xpusostomos almost 4 yearsThis syntax also ignores hidden dot files. A large number can also blow up the glob.
-
xpusostomos almost 4 yearsThat's pretty neat actually. You can also do "cp -RTf foo bar" on Linux.
-
anubhava almost 4 yearsThat can be controlled using
shopt
-
Porcupine over 3 years@Jonathan Is the end result same as the answer given above: stackoverflow.com/a/53349667/3503228
-
Porcupine over 3 years@Tom Is the end result same as the answer given below: stackoverflow.com/a/23698290/3503228
-
Jonathan Wheeler over 3 years@Porcupine The names and contents of the files should be the same, but I think that the permissions and owners will be different between the cp and rsync methods. The timestamps may also be different.
-
Porcupine over 3 years@JonathanWheeler So, which one of rsync and cp, you think, does a better job in preserving those attributes?
-
Jonathan Wheeler over 3 years@Porcupine rsync
-
Nick Roz about 3 yearsThe same answer is here stackoverflow.com/a/23698218/4175647
-
JohnyTex over 2 years. (dot) just means the current directory, no?
-
schlimmchen over 2 yearsTogether with
-a
or-p
this also makes sure that the target directory receives the metadata (owers, permissions) of the source directory -- very nice!