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

sak*_*trp 83 linux bash shell command-line cp

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

cp -Rf foo/ bar/
Run Code Online (Sandbox Code Playgroud)

会发生什么是创建一个新的bar/foo /目录.我不希望这样.foo/a和b中有两个文件.bar /中也有同名文件.我希望foo/a和foo/b替换bar/a和bar/b.

Sau*_*ram 99

您可以使用-T选项执行此操作cp.
请参阅手册页cp.

-T, --no-target-directory
    treat DEST as a normal file
Run Code Online (Sandbox Code Playgroud)

因此,根据您的示例,以下是文件结构.

$ tree test
test
|-- bar
|   |-- a
|   `-- b
`-- foo
    |-- a
    `-- b
2 directories, 4 files
Run Code Online (Sandbox Code Playgroud)

当您使用-vVerbose 时,您可以看到明显的区别.
当你只使用-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
Run Code Online (Sandbox Code Playgroud)

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

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

$ tree
|-- bar
|   |-- a
|   `-- b
`-- foo
    |-- a
    `-- b
2 directories, 4 files
Run Code Online (Sandbox Code Playgroud)

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

  • 万一有人被这个绊倒,它将不适用于OSX cp https://developer.apple.com/library/mac/documentation/Darwin/Reference/ManPages/man1/cp.1.html (18认同)
  • 目前尚不清楚这个答案是OP正在寻找什么,虽然上面给出的例子掩盖了问题......使用-T选项,现有目标中的文件(`bar /`)但*不是*source(`foo /`)将保留在原位,因此这不是大多数人认为完全覆盖目录的原因.即.如果`bar/baz`已经存在,那么它之后仍会存在...... (8认同)
  • 这个答案确实回答了 op 问题,但没有解决目标是否已经存在并且您想要删除它包含的内容但源目录不存在的情况。这不是将文件从一个地方复制到另一个地方的预期行为。它只覆盖源中的目标内容,它不会触及源中不存在的目标中的任何内容。您可以通过添加一个命令来清理目标文件夹:`rm -rf bar/* && cp -TRv foo/ bar/` (3认同)
  • 我不是读心者……我看不到 OP 正在寻找什么的进一步说明,但这绝对是我(MEEEE)正在寻找的答案 (2认同)
  • 以防万一有人被为什么点赞最多的评论中的链接不起作用而绊倒,这里是:https://web.archive.org/web/20170909193852/https://developer.apple.com/legacy/库/文档/达尔文/参考/ManPages/man1/cp.1.html (2认同)

Jon*_*ler 37

分两步完成.

rm -r bar/
cp -r foo/ bar/
Run Code Online (Sandbox Code Playgroud)

  • 这实际上是迄今为止给出的唯一**示例,它将确保`bar`在内容上与`foo`相同,而不是来自`foo`的项目组合以及可能已经存在于`bar中的其他项目.来自@Saurabh Meshram的高度赞成的回答有这个问题. (9认同)
  • 这并不总是可行的......或需要......想象一下如果`foo`和`bar`是大目录......也许`bar`中有你不想要的不在`foo`中的文件去除。恕我直言,这不应被视为现实的答案 (2认同)
  • @豪猪rsync (2认同)

Tom*_*ter 30

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

rsync -a --delete foo/ bar/
Run Code Online (Sandbox Code Playgroud)

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

  • -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).

  • 比“cp -T”选项更喜欢这个答案,因为它也适用于 macosx (3认同)

anu*_*ava 12

使用此cp命令:

cp -Rf foo/* bar/
Run Code Online (Sandbox Code Playgroud)

  • 这不会删除bar中但不存在于foo中的文件. (5认同)
  • 不知道你的意思.为什么`cp`命令要从源文件中删除文件? (3认同)
  • 此语法还会忽略隐藏的点文件。数量多也能炸毁地球。 (2认同)

Bry*_*man 9

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

$ cp -Rf foo/. bar
Run Code Online (Sandbox Code Playgroud)

  • @Mateng我刚试过它 - 是的,这是真的. (2认同)

Mic*_*itt 7

与@Jonathan Wheeler 非常相似:

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

rm -r bar/
cp -r foo/ !$
Run Code Online (Sandbox Code Playgroud)

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

  • 关于 !$ 的提示很棒! (5认同)