Come sovrascrivere i file di destinazione con mv?


155

Ho un sacco di file e directory in una sottodirectory che voglio spostare nella directory principale. Esistono già alcuni file e directory nella directory di destinazione che devono essere sovrascritti. I file presenti solo nella destinazione non devono essere toccati. Posso forzare mva farlo? Si ( mv * ..) si lamenta

mv: cannot move `xyz' to `../xyz': Directory not empty

Cosa mi sto perdendo?


3
Ci hai provato mv -f?
sabato

Mi chiedo perché mv -fnon sia la risposta corretta.
Pedro Lobito,

@PedroLobito: Perché non funziona? -f sovrascrive solo i file, ma non funziona se si spostano le sottodirectory esistenti nella destinazione e non sono vuote.
EricSchaefer,

Risposte:


118

Dovrai copiarli nella destinazione e quindi eliminare la fonte, usando i comandi cp -r * ..seguiti da rm -rf *.

Non penso che tu possa "unire" le directory usando mv.


4
Bene, questo è quello che non volevo fare, perché ci vorrà molto tempo ... Grazie comunque.
EricSchaefer,

12
Presumibilmente mvè più veloce perché sei sullo stesso filesystem? Cosa succede se si utilizza cp -lper creare collegamenti fisici anziché spostare effettivamente i file?
Mattdm,

6
È necessario utilizzare cp -aanziché cp -rper conservare gli attributi del file (data / ora, autorizzazioni, ecc.).
dotancohen,

3
Per le persone che arrivano qui in ritardo tramite google, la risposta di @palswim che segue emula il comportamento di mv creando nuovi collegamenti diretti ai dati e quindi eliminando i vecchi collegamenti. Risposta breve cp -rl source destination && rm -r source.
William Everett,

72

rsyncsarebbe probabilmente un'opzione migliore qui. È semplice come rsync -a subdir/ ./.

Il mio albero di prova in filename: contentsformato:

./file1:root
./file2:root
./dir/file3:dir
./dir/file4:dir
./subdir/dir/file3:subdir
./subdir/file1:subdir

In esecuzione rsync:

$ rsync -a -v subdir/ ./
sending incremental file list
./
file1
dir/
dir/file3

dà:

./file1:subdir
./file2:root
./dir/file3:subdir
./dir/file4:dir
./subdir/dir/file3:subdir
./subdir/file1:subdir

E quindi, per emulare mv, probabilmente si desidera rimuovere la directory di origine:

$ rm -r subdir/

Dando:

./file1:subdir
./file2:parent
./dir/file3:subdir
./dir/file4:dir

Se questo è sbagliato, puoi fornire un esempio simile (ad esempio usando il mio albero di prova nella parte superiore di questa risposta) con il risultato desiderato?


1
copie rsync. Questa domanda riguarda lo spostamento.
Gilles,

1
@Gilles: grazie. Ho aggiunto rm -ralla fine per renderlo sostanzialmente uguale a mv.
Mikel,

3
copy-then-delete non equivale a mv quando l'origine e la destinazione si trovano sullo stesso filesystem. mvè atomico, conserva i numeri di inode (quindi il file può rimanere aperto) e non richiede tempo e spazio per fare una copia.
Gilles,

5
@Gilles: me ne rendo conto, ma attualmente la risposta principale è cp -r; rm -r. Penso che in questo senso rsyncvalga la pena menzionare anche questo.
Mikel,

L'ho già fatto con cp / rm (era urgente). Ci è voluto davvero molto tempo. La sceneggiatura di Gilles sarebbe stata probabilmente molto più veloce, ma era anche troppo tardi.
EricSchaefer,

47

rsyncpuò cancellare la fonte dopo le copie con il --remove-source-filesparametro Questo dovrebbe essere un modo conveniente per fare ciò che desideri.

Dal rsync man page:

        --remove-source-files   sender removes synchronized files (non-dir)

Questa è davvero la risposta migliore. Non ho potuto usare a cp -r; rmcausa della mancanza di spazio libero. Invece rsync --remove-source-filesentrambi hanno ridotto al minimo lo spazio su disco utilizzato evitando di copiare gli stessi file.
guaka,

20

Puoi farlo con cpe rm, ma senza copiare l'enorme quantità di dati che stai (presumibilmente) stai cercando di evitare il trasferimento. @mattdm ha accennato a questo nel suo commento e una risposta per un'altra domanda ha una discussione più completa su varie opzioni.

cp -rlf source destination
rm -r source

In sostanza, l' -lopzione per il cpcomando crea collegamenti reali ai file anziché copiarne i dati in nuovi file.


1
So che l' OP ha già completato il suo compito che ha sollevato la domanda, ma spero che questa risposta possa aiutare chiunque abbia questo problema in futuro.
Palswim,

Questa è davvero la risposta di cui avevano bisogno. Ho appena fatto questo con 60 GB di migliaia di piccoli file di posta elettronica Cyrus e ci sono voluti solo 21 secondi.
labradort,

Questo è anche il percorso che ho seguito: l'ho appena cambiato cp -al source destinationper preservare le informazioni e le autorizzazioni del proprietario.
piit79,

Penso che per fare effettivamente ciò che OP ha richiesto devi aggiungere l'opzione -f altrimenti non sovrascriverà se il file esiste. Puoi confermarlo o sto facendo qualcosa di sbagliato?
das Keks,

@dasKeks: in realtà, cpsovrascrive per impostazione predefinita. L' -fopzione tenta di rimuovere il file (come in rm) prima di provare a copiarlo di nuovo, il che può aiutare se il processo non è in grado di aprire il file per la scrittura, anche se alcune persone preferiscono vedere che si è verificato invece un errore. Non so se fosse importante per l'OP, ma ho comunque aggiunto la -fbandiera alla mia risposta.
Palswim,

8

Ecco uno script che sposta i file da sotto /path/to/source/rootal percorso corrispondente sotto /path/to/destination/root.

  • Se esiste una directory sia nell'origine che nella destinazione, i contenuti vengono spostati e uniti in modo ricorsivo.
  • Se esiste un file o una directory nell'origine ma non nella destinazione, viene spostato.
  • Qualsiasi file o directory già esistente nella destinazione viene lasciato indietro. (In particolare le directory unite vengono lasciate indietro nella fonte. Non è facile da risolvere.)

Attenzione, codice non testato.

export dest='/path/to/destination/root'
cd /path/to/source/root
find . -type d \( -exec sh -c '[ -d "$dest/$0" ]' \; -o \
                  -exec sh -c 'mv "$0" "$dest/$0"' {} \; -prune \) \
    -o -exec sh -c '
        if ! [ -e "$dest/$0" ]; then
          mv -f "$0" "$dest/$0"
        fi
' {} \;

Due correzioni: hai bisogno di una \;prima della -oprima riga del findcomando e non dovresti scappare !nella if- è solo !, non\!
llhuii

2

Questo thread è disponibile da anni e si colloca al primo posto su google, quindi volevo aggiungere un altro metodo. Come faccio di solito questo: comprimendo il contenuto del subdir in un tarball, spostando il tarball nella directory principale e quindi estraendolo con il comportamento predefinito - overwrite. Questo fa esattamente quello che stai cercando. Successivamente puoi rimuovere il tuo sottodir.

cd xyz
tar -cvzpf tmp.tar.gz *
mv tmp.tar.gz ../tmp.tar.gz
cd ..
tar -xvzpf tmp.tar.gz
rm -rf xyz
rm -f tmp.tar.gz

Funziona solo se hai lo spazio extra per il file tar compresso. E vuoi davvero mantenere il file tar temporaneo in giro dopo l'estrazione?
Anthon,

Codice modificato per rimuovere il file tmp. Oggi lo spazio non è il problema nella maggior parte dei casi. #terabyteages
Simon Kraus,

0

Se hai abbastanza spazio di archiviazione, puoi farlo nel modo seguente:

mv -bfv directory_1/* directory_2/ # all duplicate source files/directories 
                                   # will have ~ appended to them
find -name "*~" -delete            # will recursively find and delete all files 
                                   # with ~ on the end

Assicurati che non ci siano file importanti con un ~ alla fine di essi, ma se ci sono puoi aggiungere --suffix=whateveryouwantinvece i valori predefiniti.

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.