Come forzare 'cp' a sovrascrivere la directory invece di crearne un'altra all'interno?


107

Sto cercando di scrivere uno script Bash che sovrascriverà una directory esistente. Ho una directory foo/e sto cercando di sovrascriverla bar/. Ma quando lo faccio:

cp -Rf foo/ bar/

bar/foo/viene creata una nuova directory. Non lo voglio. Ci sono due file in foo/; ae b. Ci sono anche file con lo stesso nome bar/. Voglio che foo/ae foo/bsostituisca bar/ae bar/b.

Risposte:


122

Puoi farlo usando l' -Topzione in cp.
Vedere la pagina man per cp.

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

Quindi, come nel tuo esempio, la seguente è la struttura del file.

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

Puoi vedere la chiara differenza quando usi -vper Verbose.
Quando usi solo l' -Ropzione.

$ 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 si utilizza l'opzione, -Tsi sovrascrive il contenuto, trattando la destinazione come un normale file e non come una directory .

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

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

Questo dovrebbe risolvere il tuo problema.


22
solo nel caso in cui qualcuno sia inciampato da questo non funzionerà con OSX cp developer.apple.com/library/mac/documentation/Darwin/Reference/…
dnfehren

9
Non è chiaro se questa risposta sia ciò che l'OP sta cercando, anche se gli esempi forniti sopra mascherano il problema ... Con l'opzione -T, i file che si trovano in una destinazione esistente ( bar/) ma non nella sorgente ( foo/) verranno lasciati in atto, quindi questo non è ciò che la maggior parte delle persone considererebbe una sovrascrittura completa della directory. vale a dire. se bar/bazesistesse già, esisterebbe ancora in seguito ...
robo

1
Questa risposta risponde alla domanda op, ma non affronta il caso in cui la destinazione esiste già e si desidera rimuovere i contenuti che contiene ma la directory di origine no. Questo non è un comportamento previsto per la copia dei file da una posizione all'altra. Sovrascrive nella destinazione solo le cose che sono anche nella sorgente, non tocca nulla nella destinazione che non è nella sorgente. Puoi pulire la cartella di destinazione anteponendo un comando per farlo:rm -rf bar/* && cp -TRv foo/ bar/
theferrit32

1
Non sono un lettore mentale ... Non vedo ulteriori chiarimenti su ciò che l'OP stava cercando, ma questa era SICURAMENTE la risposta che io (MEEEE) stavo cercando
Assimilater

2
nel caso qualcuno sia inciampato dal motivo per cui il link nel commento più votato non funziona, eccolo: web.archive.org/web/20170909193852/https://developer.apple.com/…
Sulphur

48

Fallo in due passaggi.

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

11
Questo è in realtà l' unico esempio fornito finora che garantirà che barsia identico nel contenuto a foo, non una combinazione di elementi da foopiù altri elementi che potrebbero essere già esistiti in bar. La risposta altamente votata da @Saurabh Meshram di seguito presenta questo problema.
robo

1
Essere molto attenti con questo, in quanto sarà rimuovere tutti i file dalla barra, anche quelli nascosti.
Elia Grady

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

1
Questo non è sempre praticabile ... o desiderato ... immagina se fooe barsono directory di grandi dimensioni ... forse ci sono file barche non sono in fooche non vuoi rimuovere. Questa non dovrebbe essere considerata una risposta realistica imho
Assimilater

Anche se ha funzionato per me, ma non è la soluzione migliore poiché potrebbe esserci un file incluso in foo / ma non in bar / che verrà eliminato dopo averlo fatto.
Nitwit

46

Se vuoi assicurarti che sia bar/identico a foo/, usa rsyncinvece:

rsync -a --delete foo/ bar/

Se solo alcune cose sono cambiate, verrà eseguito molto più velocemente rispetto alla rimozione e alla ricopia dell'intera directory.

  • -aè 'modalità archivio', che copia i file fedelmente foo/abar/
  • --deleterimuove i file aggiuntivi non foo/da bar/pure, assicurando bar/finisce identici
  • Se vuoi vedere cosa sta facendo, aggiungi -vhper verboso e leggibile dall'uomo
  • Nota: la barra dopo fooè richiesta, altrimenti rsyncverrà copiata foo/in bar/foo/anziché sovrascrivere bar/se stessa.
    • (Le barre dopo le directory in rsync creano confusione; se sei interessato, ecco lo scoop. Dicono a rsync di fare riferimento al contenuto della directory, piuttosto che alla directory stessa . Quindi, per sovrascrivere dal contenuto di foo/sul contenuto di bar/, noi usa una barra su entrambi. È fonte di confusione perché non funzionerà come previsto con una barra su nessuno dei due , però; rsync interpreta sempre furtivamente il percorso di destinazione come se avesse una barra, anche se onora l'assenza di una barra sull'origine percorso. Quindi abbiamo bisogno di una barra sul percorso di origine per farla corrispondere alla barra aggiunta automaticamente sul percorso di destinazione, se vogliamo copiare il contenuto di foo/in bar/, piuttosto che nella directoryfoo/stesso atterrando in bar/come bar/foo.)

rsync è molto potente e utile, se sei curioso guardati intorno per cos'altro può fare (come copiare su ssh).


1
Ti piace questa risposta meglio cp -Tdell'opzione perché funziona anche su macosx 👍
tongueroo

18

Usa questo cpcomando:

cp -Rf foo/* bar/

9
Questo non rimuove i file che sono presenti in bar ma non in foo.
Ara

5
Non so cosa intendi con questo. Perché il cpcomando dovrebbe rimuovere il file dall'origine?
anubhava

La mia comprensione era che quando si "sovrascrive una directory esistente" con un'altra, alla fine la directory sovrascritta dovrebbe essere una copia dell'altra. Cioè alla fine della barra dovrebbe esserci una copia di pippo, come nel caso della risposta @ jonathan-wheeler, ma se hai una barra dei file / ce nessun pippo / c, la barra / c non viene eliminata. In una nota a margine, ho appena notato che non è nemmeno il caso della risposta di Saurabh Meshram.
Ara

Forse non siamo d'accordo su cosa significhi sovrascrivere, per me è fondamentalmente sostituire, mentre potresti intendere megre? È difficile dire cosa vuole esattamente OP perché ha menzionato solo 2 file che sono sia in foo che in bar.
Ara

Questa sintassi ignora anche i file di punti nascosti. Un numero elevato può anche far saltare in aria il globo.
xpusostomos

13

Il seguente comando garantisce che i dotfile (file nascosti) siano inclusi nella copia:

$ cp -Rf foo/. bar

1
È vero? Sembra insolito.
Mateng

2
@ Mateng l'ho appena testato - sì, è vero.
Matmarbon

1
.significa tutti i file nella directory. Quindi, naturalmente, i file nascosti sarebbero inclusi.
Jaspreet Singh

In realtà è abbastanza carino. Puoi anche fare "cp -RTf foo bar" su Linux.
xpusostomos

5

Molto simile a @Jonathan Wheeler:

Se non vuoi ricordare, ma non riscrivere bar:

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

!$ mostra l'ultimo argomento del comando precedente.


4
Il suggerimento su! $ È fantastico!
Lucas Morgan

0

Questo dovrebbe risolvere il tuo problema.

\cp -rf foo/* bar/

-1

L'operazione che hai definito è una "fusione" e non puoi farlo cp. Tuttavia, se non stai cercando l'unione e ok per perdere la cartella bar, puoi semplicemente rm -rf bareliminare la cartella e quindi mv foo barrinominarla. Ciò non richiederà tempo poiché entrambe le operazioni vengono eseguite da puntatori di file, non dal contenuto del file.


-2

Prova a usare questo comando composto da due passaggi:

rm -rf bar && cp -r foo bar
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.