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

LinuxBashShellCommand LineCp

Linux Problem Overview


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.

Linux Solutions


Solution 1 - Linux

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 - Linux

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 - Linux

Do it in two steps.

rm -r bar/
cp -r foo/ bar/

Solution 4 - Linux

Use this cp command:

cp -Rf foo/* bar/

Solution 5 - Linux

The following command ensures dotfiles (hidden files) are included in the copy:

$ cp -Rf foo/. bar

Solution 6 - Linux

Very similar to @Jonathan Wheeler:

If you do not want to remember, but not rewrite bar:

rm -r bar/
cp -r foo/ !$

!$ displays the last argument of your previous command.

Solution 7 - Linux

this should solve your problem.

\cp -rf foo/* bar/

Solution 8 - Linux

In case you're in Git Bash for Windows:

robocopy path/to/source path/to/target -MIR

-MIR means mirror, it'll result in two identical folders. Existing files will be skipped, extra files will be deleted.

Solution 9 - Linux

The operation you defined is a "merge" and you cannot do that with cp. However, if you are not looking for merging and ok to lose the folder bar then you can simply rm -rf bar to delete the folder and then mv foo bar to rename it. This will not take any time as both operations are done by file pointers, not file contents.

Solution 10 - Linux

Try to use this composed of two steps command:

cp -Rf foo/* bar/

Attributions

All content for this solution is sourced from the original question on Stackoverflow.

The content on this page is licensed under the Attribution-ShareAlike 4.0 International (CC BY-SA 4.0) license.

Content TypeOriginal AuthorOriginal Content on Stackoverflow
QuestionsaketrpView Question on Stackoverflow
Solution 1 - LinuxSaurabh MeshramView Answer on Stackoverflow
Solution 2 - LinuxTom PotterView Answer on Stackoverflow
Solution 3 - LinuxJonathan WheelerView Answer on Stackoverflow
Solution 4 - LinuxanubhavaView Answer on Stackoverflow
Solution 5 - LinuxMay OakesView Answer on Stackoverflow
Solution 6 - LinuxMichael DimmittView Answer on Stackoverflow
Solution 7 - LinuxaliView Answer on Stackoverflow
Solution 8 - LinuxZYinMDView Answer on Stackoverflow
Solution 9 - LinuxAtiView Answer on Stackoverflow
Solution 10 - LinuxYahor MView Answer on Stackoverflow