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.