如何强制'cp'覆盖目录而不是在里面创建另一个?

问题描述 投票:69回答:8

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

cp -Rf foo/ bar/

创建一个新的bar/foo/目录。我不希望这样。 foo/中有两个文件; abbar/中也有相同名称的文件。我希望foo/afoo/b取代bar/abar/b

linux bash shell command-line cp
8个回答
91
投票

您可以使用-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

当您使用-v作为详细时,您可以看到明显的区别。 当你只使用-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

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


34
投票

分两步完成。

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

20
投票

如果你想确保bar/最终与foo/相同,请改用rsync

rsync -a --delete foo/ bar/

如果只是改变了一些事情,这将比删除和重新复制整个目录快得多。

  • -a是'存档模式',它忠实地将foo/中的文件复制到bar/
  • --delete也从foo/删除不在bar/中的额外文件,确保bar/最终完全相同
  • 如果你想看看它在做什么,添加-vh用于详细和人类可读
  • 注意:需要在foo之后的斜线,否则rsync会将foo/复制到bar/foo/而不是覆盖bar/本身。 (在rsync中的目录之后的斜杠令人困惑;如果你感兴趣,这里是scoop。它们告诉rsync引用目录的内容,而不是目录本身。所以要从foo/的内容覆盖到bar/的内容但是我们在两者上都使用斜杠。它很混乱,因为它不会像预期的那样工作,但两者都没有斜线; rsync偷偷地总是将目标路径解释为有斜线,即使它表示没有斜杠如果我们想将foo/的内容复制到bar/而不是目录foo/本身登陆bar/作为bar/foo,那么我们需要在源路径上使用斜杠以使其与目标路径上的自动添加斜杠匹配。)

rsync是非常强大和有用的,如果你好奇地看看它能做什么(比如复制ssh)。


10
投票

使用此cp命令:

cp -Rf foo/* bar/

7
投票

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

$ cp -Rf foo/. bar

3
投票

与@Jonathan Wheeler非常相似:

如果你不想记住,但不要重写bar

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

!$显示上一个命令的最后一个参数。


-1
投票

您定义的操作是“合并”,您不能使用cp执行此操作。但是,如果你不想合并并且可以丢失文件夹bar那么你可以简单地rm -rf bar删除文件夹然后mv foo bar重命名它。这不会花费任何时间,因为两个操作都是由文件指针完成的,而不是文件内容。


-1
投票

尝试使用这两步命令组成:

rm -rf bar && cp -r foo bar
© www.soinside.com 2019 - 2024. All rights reserved.