Como forçar 'cp' a sobrescrever o diretório em vez de criar outro dentro?


107

Estou tentando escrever um script Bash que substituirá um diretório existente. Tenho um diretório foo/e estou tentando substituí bar/-lo. Mas quando eu faço isso:

cp -Rf foo/ bar/

um novo bar/foo/diretório é criado. Eu não quero isso. Existem dois arquivos em foo/; ae b. Também há arquivos com os mesmos nomes bar/. Quero que foo/ae foo/bsubstitua bar/ae bar/b.

Respostas:


122

Você pode fazer isso usando a -Topção em cp.
Consulte a página do manual para cp.

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

Portanto, de acordo com seu exemplo, a seguir está a estrutura do arquivo.

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

Você pode ver a diferença clara quando você usa -vpara Verbose.
Quando você usa apenas a -Ropção.

$ 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

Quando você usa a opção, -Tela sobrescreve o conteúdo, tratando o destino como um arquivo normal e não como um diretório .

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

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

Isso deve resolver seu problema.


22
caso alguém se atrapalhe com isso, não funcionará com OSX cp developer.apple.com/library/mac/documentation/Darwin/Reference/…
dnfehren

9
Não está claro se esta resposta é o que o OP está procurando, embora os exemplos dados acima mascarem o problema ... Com a opção -T, os arquivos que estão em um destino existente ( bar/), mas não na origem ( foo/) serão deixados em vigor, portanto, isso não é o que a maioria das pessoas consideraria uma substituição completa do diretório. ie. se bar/bazjá existisse, ainda existiria depois ...
robo

1
Esta resposta responde à pergunta op, mas não aborda o caso de se o destino já existe e você deseja remover o conteúdo que ele contém, mas o diretório de origem não. Este não é um comportamento esperado de copiar arquivos de um lugar para outro. Ele apenas sobrescreve no destino coisas que também estão na origem, não toca em nada no destino que não esteja na origem. Você pode limpar a pasta de destino adicionando um comando para fazer isso:rm -rf bar/* && cp -TRv foo/ bar/
theferrit32

1
Não sou um leitor de mentes ... Não vejo mais esclarecimentos sobre o que o OP estava procurando, mas esta era DEFINITIVAMENTE a resposta que eu (MEEEE) estava procurando
Assimilater

2
apenas no caso de alguém se enganar com o motivo do link do comentário mais votado não estar funcionando, aqui está: web.archive.org/web/20170909193852/https://developer.apple.com/…
Enxofre

48

Faça isso em duas etapas.

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

11
Na verdade, este é o único exemplo dado até agora que garantirá que o barconteúdo seja idêntico a foo, e não uma combinação de itens de foomais outros itens que possam já existir em bar. A resposta altamente votada por @Saurabh Meshram abaixo tem esse problema.
robo

1
Tenha muito cuidado ao usar isso, pois irá remover todos os arquivos do bar, mesmo os mais ocultos.
Elia Grady

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

1
Isso nem sempre é viável ... ou desejado ... imagine se fooe barforem grandes diretórios ... talvez haja arquivos barque não estão dentro e fooque você não deseja remover. Esta não deve ser considerada uma resposta realista imho
Assimilater

Embora funcionou para mim, mas não a melhor solução, uma vez que pode haver arquivo incluído em foo / mas não em bar / que será excluído após fazer isso.
Nitwit

46

Se você deseja garantir que bar/termina idêntico a foo/, use em seu rsynclugar:

rsync -a --delete foo/ bar/

Se apenas algumas coisas mudaram, isso será executado muito mais rápido do que remover e copiar todo o diretório.

  • -aé o 'modo de arquivo', que copia arquivos fielmente foo/parabar/
  • --deleteremove arquivos extras não na foo/de bar/bem, garantindo bar/acaba idênticos
  • Se você quiser ver o que está fazendo, adicione -vhpara verboso e legível
  • Nota: a barra após fooé necessária, caso contrário, rsyncserá copiado foo/em bar/foo/vez de sobrescrito bar/.
    • (As barras após os diretórios em rsync são confusas; se você estiver interessado, aqui está o furo. Eles dizem ao rsync para se referir ao conteúdo do diretório, em vez do próprio diretório . Portanto, para substituir o conteúdo de foo/no conteúdo debar/ , nós use uma barra em ambos. É confuso porque não funcionará como esperado com uma barra em nenhum ; rsync sorrateiramente sempre interpreta o caminho de destino como se tivesse uma barra, embora respeite a ausência de uma barra na origem caminho. Portanto, precisamos de uma barra no caminho de origem para que corresponda à barra adicionada automaticamente no caminho de destino, se quisermos copiar o conteúdo defoo/ para bar/, em vez do diretóriofoo/pousando em bar/como bar/foo.)

rsync é muito poderoso e útil, se você estiver curioso, procure o que mais ele pode fazer (como copiar sobre ssh).


1
Gostei desta resposta melhor do que a cp -Topção porque também funciona em macosx 👍
tongueroo

18

Use este cpcomando:

cp -Rf foo/* bar/

9
Isso não remove arquivos que estão presentes em bar, mas não em foo.
Ara

5
Não sei o que você quer dizer com isso. Por que o cpcomando deve remover o arquivo da fonte?
anubhava 01 de

Meu entendimento é que quando você 'sobrescreve um diretório existente' por outro, no final o diretório sobrescrito deve ser uma cópia do outro. Ou seja, na barra final deve haver uma cópia de foo, como é o caso de @jonathan-wheeler answer, mas se você tivesse um arquivo bar / ce nenhum foo / c, então bar / c não seria excluído. Em uma nota lateral, acabei de notar que também não é o caso da resposta de Saurabh Meshram.
Ara

Talvez não concordemos sobre o que significa sobrescrever, para mim é basicamente substituir, enquanto você pode significar megre? É difícil dizer o que OP deseja exatamente porque ela mencionou apenas 2 arquivos que estão em foo e bar.
Ara

Essa sintaxe também ignora arquivos de ponto ocultos. Um grande número também pode explodir o globo.
xpusostomos

13

O seguinte comando garante que dotfiles (arquivos ocultos) sejam incluídos na cópia:

$ cp -Rf foo/. bar

1
Isso é verdade? Parece incomum.
Mateng

2
@Mateng Acabei de testar - sim, é verdade.
Matmarbon

1
.significa todos os arquivos do diretório. Então, naturalmente, os arquivos ocultos seriam incluídos.
Jaspreet Singh

Isso é muito legal, na verdade. Você também pode fazer "cp -RTf foo bar" no Linux.
xpusostomos

5

Muito semelhante a @Jonathan Wheeler:

Se você não quer lembrar, mas não reescrever bar:

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

!$ exibe o último argumento do comando anterior.


4
A dica sobre o! $ É incrível!
Lucas Morgan

0

isso deve resolver seu problema.

\cp -rf foo/* bar/

-1

A operação que você definiu é uma "fusão" e você não pode fazer isso com ela cp. No entanto, se você não estiver procurando por mesclagem e barpuder perder a pasta , basta rm -rf barexcluir a pasta e mv foo barrenomeá-la. Isso não levará nenhum tempo, pois ambas as operações são feitas por ponteiros de arquivo, não pelo conteúdo do arquivo.


-2

Tente usar este comando composto de duas etapas:

rm -rf bar && cp -r foo bar
Ao utilizar nosso site, você reconhece que leu e compreendeu nossa Política de Cookies e nossa Política de Privacidade.
Licensed under cc by-sa 3.0 with attribution required.