如何强制“ cp”覆盖目录而不是在内部创建另一个目录?


107

我正在尝试编写一个Bash脚本,它将覆盖现有目录。我有一个目录foo/,我正在尝试bar/用它覆盖。但是当我这样做时:

cp -Rf foo/ bar/

bar/foo/创建一个新目录。我不要 其中有两个文件foo/ab。也有相同名称的文件bar/。我想要foo/afoo/b替换bar/abar/b

Answers:


122

您可以使用中的-T选项来执行此操作cp
参见手册页cp

-T, --no-target-directory
    treat DEST as a normal file

因此,按照您的示例,以下是文件结构。

$ tree test
test
|-- bar
|   |-- a
|   `-- b
`-- foo
    |-- a
    `-- b
2 directories, 4 files

当您使用-vVerbose 时,可以看到明显的区别。
当您使用just -R选项时。

$ 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

使用该选项时,-T它将覆盖内容,将目标视为普通文件而不是目录

$ cp -TRv foo/ bar/
`foo/b' -> `bar/b'
`foo/a' -> `bar/a'

$ tree
|-- bar
|   |-- a
|   `-- b
`-- foo
    |-- a
    `-- b
2 directories, 4 files

这应该可以解决您的问题。



9
虽然上面给出的示例掩盖了问题,但尚不清楚此答案是OP所寻找的。使用-T选项,将保留现有目标(bar/)中而不是源(foo/)中的文件。到位,所以这不是大多数人认为完全覆盖目录的方式。即。如果bar/baz已经存在,它将在以后仍然存在...
robo

1
此答案确实回答了op问题,但没有解决以下情况:目标已经存在,并且您要删除其包含的内容,但源目录不存在。这不是将文件从一个位置复制到另一位置的预期行为。它只会覆盖目标中也包含源的内容,不会触及目标中不包含源的任何内容。您可以通过添加命令来清理目标文件夹:rm -rf bar/* && cp -TRv foo/ bar/
theferrit32 '17

1
我不是头脑读者...我没有看到进一步澄清操作程序正在寻找什么,但这绝对是我(MEEEE)正在寻找的答案
Assimilater

2
万一有人用,为什么在最upvoted评论的链接不工作绊倒了,那就是:web.archive.org/web/20170909193852/https://developer.apple.com/...

48

分两步完成。

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

11
实际上,这是迄今为止给出的唯一示例,它将确保bar内容与相同foo,而不是来自的项目foo加上可能已经存在的其他项目的组合bar。下面的@Saurabh Meshram极力支持的答案存在此问题。
robo

1
使用此工具时要格外小心,因为它删除bar中的所有文件,甚至是隐藏文件。
Elia Grady

mac osx: rm -rf bar/; cp -r foo/ !$
Michael Dimmitt

1
这并不总是可行的……或不理想……想象如果目录很大,foo并且bar……其中某些文件bar不是foo您不想删除的。这不应该是一个现实的答案,恕我直言
Assimilater

虽然对我有用,但不是最好的解决方案,因为foo /中可能包含文件,而bar /中却没有,执行此操作后将删除该文件。
Nitwit

46

如果要确保bar/最终结果与相同foo/,请rsync改用:

rsync -a --delete foo/ bar/

如果仅有几处更改,则此操作的执行速度将比删除并重新复制整个目录快得多。

  • -a是“存档模式”,可将文件如实复制foo/bar/
  • --delete删除多余的文件不是foo/bar/为好,以确保bar/各上调相同
  • 如果您想了解它在做什么,请添加-vh详细信息并易于阅读
  • 注意:后面的斜杠foo是必需的,否则rsync将复制foo/bar/foo/而不是覆盖bar/自身。
    • (在rsync的目录后斜杠混乱;如果你有兴趣,这里的勺子他们让rsync参考。内容的目录,而不是目录本身所以从覆盖。内容foo/到的内容bar/,我们使用斜线上都它的混乱,因为它会如预期与斜线不工作。没有,虽然,rsync的鬼祟总是解释的目标路径,就好像它有一个斜杠,即使它崇没有斜线的来源路径。因此,我们需要的源路径上的斜线,使其目标路径上匹配自动添加斜线,如果我们想将复制内容foo/进入bar/,而不是目录foo/本身落地成bar/bar/foo。)

rsync 是非常强大且有用的,如果您好奇地看一下它还能做什么(例如通过ssh复制)。


1
像这样的答案比cp -T选项更胜一筹,因为它也适用于macosx👍–
fingerroo

18

使用此cp命令:

cp -Rf foo/* bar/

9
这不会删除bar中存在但foo中不存在的文件。
2015年

5
不知道那是什么意思。为什么cp命令应该从源中删除文件?
anubhava 2015年

我的理解是,当您用另一个“覆盖现有目录”时,最后被覆盖的目录应该是另一个目录的副本。即在结尾的bar应该是foo的副本,就像@ jonathan-wheeler答案一样,但是如果您有文件bar / c而没有foo / c,那么bar / c不会被删除。附带一提,我刚刚注意到,Saurabh Meshram的回答也不是这种情况。
2015年

也许我们不同意覆写的含义,对我来说,它基本上是替代品,而您可能意味巨大?很难说出OP到底想要什么,因为她只提到了foo和bar中的2个文件。
2015年

此语法还忽略隐藏的点文件。大量也可能炸毁这个球。
xpusostomos

13

以下命令确保副本中包含点文件(隐藏文件):

$ cp -Rf foo/. bar

1
这是真的?看起来不寻常。
马滕

2
@Mateng我刚刚测试过-是的。
Matmarbon

1
.表示目录中的所有文件。因此,自然会包含隐藏文件。
Jaspreet Singh '18

实际上,这很整洁。您也可以在Linux上执行“ cp -RTf foo bar”。
xpusostomos


0

这应该可以解决您的问题。

\cp -rf foo/* bar/

-1

您定义的操作是“合并”,您不能使用进行操作cp。但是,如果您不希望合并并且可以丢失文件夹,bar则只需rm -rf bar删除该文件夹然后mv foo bar重命名即可。这不会花费任何时间,因为这两个操作都是由文件指针而不是文件内容完成的。


-2

尝试使用由两个步骤组成的命令:

rm -rf bar && cp -r foo bar
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.