How to force 'cp' to overwrite directory instead of creating another one inside?

198,902

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 in foo/ to bar/
  • --delete removes extra files not in foo/ from bar/ as well, ensuring bar/ 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, otherwise rsync will copy foo/ to bar/foo/ rather than overwriting bar/ 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 of bar/, 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 of foo/ into bar/, rather than the directory foo/ itself landing into bar/ as bar/foo.)

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
Share:
198,902

Related videos on Youtube

saketrp
Author by

saketrp

Updated on July 08, 2022

Comments

  • saketrp
    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 overwrite bar/ 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 in foo/; a and b. There are files with same names in bar/ as well. I want the foo/a and foo/b to replace bar/a and bar/b.

  • Ara
    Ara about 9 years
    This doesn't remove files that are present in bar but not in foo.
  • anubhava
    anubhava about 9 years
    Don't know what you mean by that. Why should cp command be removing file from source?
  • Ara
    Ara about 9 years
    My 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
    Ara about 9 years
    Maybe 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
    dnfehren over 8 years
    just in case anyone is tripped up by this it won't work with OSX cp developer.apple.com/library/mac/documentation/Darwin/Referen‌​ce/…
  • Mateng
    Mateng over 7 years
    Is this true? Looks unusual.
  • robo
    robo over 7 years
    It'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. if bar/baz existed already, it would still exist afterwards...
  • robo
    robo over 7 years
    This is actually the only example given so far that will ensure that bar is identical in content to foo, not a combination of items from foo plus other items that may have already existed in bar. The highly upvoted answer from @Saurabh Meshram below has this problem.
  • Elia Grady
    Elia Grady almost 7 years
    Be extra careful using this, as it will remove all files from bar, even hidden ones.
  • Matmarbon
    Matmarbon almost 7 years
    @Mateng I just tested it - yes it is true.
  • JohnyTex
    JohnyTex over 6 years
    Is there no option to clean target folder in the process? I can't believe it!
  • Michael Dimmitt
    Michael Dimmitt over 6 years
    mac osx: rm -rf bar/; cp -r foo/ !$
  • theferrit32
    theferrit32 over 6 years
    This 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
    Lucas over 6 years
    The tip about the !$ is awesome!
  • Jaspreet Singh
    Jaspreet Singh almost 6 years
    . means all the files in the directory. So, naturally the hidden files would be included.
  • tongueroo
    tongueroo over 5 years
    Like this answer better than the cp -T option because it also works on macosx 👍
  • Assimilater
    Assimilater over 5 years
    This isn't always viable...or desired...imagine if foo and bar are large directories...maybe there are files in bar that are not in foo that you don't want to remove. This shouldn't be considered a realistic answer imho
  • Assimilater
    Assimilater over 5 years
    I'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
    Sulphur over 4 years
    just 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.c‌​om/…
  • Nitwit
    Nitwit about 4 years
    Although 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
    qwr almost 4 years
    @robo and also the rsync answer now
  • xpusostomos
    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
    xpusostomos almost 4 years
    This syntax also ignores hidden dot files. A large number can also blow up the glob.
  • xpusostomos
    xpusostomos almost 4 years
    That's pretty neat actually. You can also do "cp -RTf foo bar" on Linux.
  • anubhava
    anubhava almost 4 years
    That can be controlled using shopt
  • Porcupine
    Porcupine over 3 years
    @Jonathan Is the end result same as the answer given above: stackoverflow.com/a/53349667/3503228
  • Porcupine
    Porcupine over 3 years
    @Tom Is the end result same as the answer given below: stackoverflow.com/a/23698290/3503228
  • Jonathan Wheeler
    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
    Porcupine over 3 years
    @JonathanWheeler So, which one of rsync and cp, you think, does a better job in preserving those attributes?
  • Jonathan Wheeler
    Jonathan Wheeler over 3 years
    @Porcupine rsync
  • Nick Roz
    Nick Roz about 3 years
    The same answer is here stackoverflow.com/a/23698218/4175647
  • JohnyTex
    JohnyTex over 2 years
    . (dot) just means the current directory, no?
  • schlimmchen
    schlimmchen over 2 years
    Together with -a or -p this also makes sure that the target directory receives the metadata (owers, permissions) of the source directory -- very nice!