Risposte:
mv
impossibile unire o sovrascrivere le directory, fallirà con il messaggio "mv: impossibile spostare" a "in" b ": directory non vuota" , anche quando si utilizza l' --force
opzione.
È possibile aggirare questo utilizzando altri strumenti (come rsync
, find
o anche cp
), ma è necessario considerare con attenzione le implicazioni:
rsync
può unire i contenuti di una directory in un'altra (idealmente con l' opzione --remove-source-files
1 per eliminare in modo sicuro solo i file di origine che sono stati trasferiti correttamente e con la consueta opzione di autorizzazione / proprietà / conservazione del tempo -a
se lo si desidera) rsync
l' --link-dest=DIR
opzione (per creare collegamenti fissi invece di copiare il contenuto del file, ove possibile) e --remove-source-files
ottenere una semantica molto simile a una normale mv
. --link-dest
deve essere assegnato un percorso assoluto alla directory di origine (o un percorso relativo dalla destinazione alla fonte ). --link-dest
in modo non intenzionale (che può o meno causare complicazioni), richiede di conoscere (o determinare) il percorso assoluto verso la fonte (come argomento per --link-dest
), e di nuovo lascia una struttura di directory vuota da ripulire come per 1 .find
per ricreare in sequenza la struttura della directory di origine sulla destinazione, quindi spostare individualmente i file effettivi cp
può creare collegamenti fissi (semplicemente, puntatori aggiuntivi allo stesso file esistente), che crea un risultato molto simile a una fusione mv
(ed è molto efficiente in termini di IO poiché vengono creati solo puntatori e non è necessario copiare dati effettivi) Quale di queste soluzioni alternative (se presenti) è appropriata dipenderà molto dal tuo caso d'uso specifico.
Come sempre, pensa prima di eseguire uno di questi comandi e disponi di backup.
1: Nota che rsync --remove-source-files
non cancellerai nessuna directory, quindi dovrai fare qualcosa come find -depth -type d -empty -delete
dopo per sbarazzarti della struttura della directory dei sorgenti vuota.
mv
implementazione usata da Debian - l'enfasi è stata provata , dato che la manpage non menziona questo comportamento ...
--delete
elimina solo i file nella directory di destinazione che non esistono nella directory di origine.
-H
fisici con la funzione o puoi collegare i file nella destinazione usando --link-dest
. Vedi la pagina man prima di usarli, però.
rsync -av /source/ /destination/
(after checking)
rm -rf /source/
--remove-source-files
ha il vantaggio di rimuovere solo i file che sono stati trasferiti correttamente, quindi è possibile utilizzare find
per rimuovere directory vuote e verrà lasciato con tutto ciò che non è stato trasferito senza dover controllare l' rsync
output.
È possibile utilizzare l' -l
opzione del comando cp , che crea collegamenti reali di file sullo stesso filesystem anziché copie complete. Il comando seguente copia la cartella source/folder
in una cartella principale ( destination
) che contiene già una directory con il nome folder
.
cp -rl source/folder destination
rm -r source/folder
Puoi anche utilizzare il -P
( --no-dereference
- non rimandare i collegamenti simbolici) o -a
( --archive
- conservare tutti i metadati, include anche l' -P
opzione), a seconda delle tue esigenze.
cp
piuttosto che da rsync
quando ogni sistema ha cp
e tutti hanno familiarità con esso.
cp
con il tempo di operazione di mv
.
-n
mv /fs1/file /fs2/
(attraverso i filesystem) eseguirà una copia e quindi una cancellazione.
mv
funzionerà (a condizione che la directory di destinazione non esista ancora) anche se non "in modo efficiente" o come la chiami, cp -rl
fallirà.
Consiglierei questi quattro passaggi:
cd ${SOURCE};
find . -type d -exec mkdir -p ${DEST}/\{} \;
find . -type f -exec mv \{} ${DEST}/\{} \;
find . -type d -empty -delete
o meglio ancora, ecco uno script che implementa la semantica simile a mv
:
#!/bin/bash
DEST="${@:${#@}}"
ABS_DEST="$(cd "$(dirname "$DEST")"; pwd)/$(basename "$DEST")"
for SRC in ${@:1:$((${#@} -1))}; do (
cd "$SRC";
find . -type d -exec mkdir -p "${ABS_DEST}"/\{} \;
find . -type f -exec mv \{} "${ABS_DEST}"/\{} \;
find . -type d -empty -delete
) done
rsync -u
(aggiorna solo se più recente), mv
(almeno in alcune versioni) puoi anche prendere l' -u
opzione. Tuttavia, in tal caso, potresti voler eliminare le directory dei sorgenti non vuote e anche quelle vuote, per coprire i casi in cui i file nella struttura dei sorgenti non sono più recenti. @schuess: sembra che ci possano essere più argomenti SOURCE, se ne hai bisogno.
Ecco un modo che unirà le directory. È molto più veloce di rsync dal momento che rinomina i file invece di copiarli e quindi eliminarli.
cd source; find -type f -print0 | xargs -0 -n 1 -I {} mv '{}' 'dest/{}'
dest
è già una directory con lo stesso nome di in source
. E i file verranno spostati in a dest
, che è in source
. Il comando non fa altro chemv source/* source/dest/.
Un modo per ottenere ciò sarebbe usare:
mv folder/* directory/folder/
rmdir folder
Finché non ci sono due file con lo stesso nome folder
e directory/folder
, otterrai lo stesso risultato, ovvero l'unione.
rm folder
?
rm folder -fR
funziona sempre per me
Per le copie più pure, uso il metodo di copia blockread tar (-) B.
esempio, dal percorso sorgente ('cd' lì se necessario):
tar cBf - <sourcefolder> | (cd /your/target/folder ; tar xBf -)
questo crea una copia esatta dell'albero dei sorgenti, con il proprietario e le autorizzazioni intatte. E se esiste la cartella di destinazione, i dati verranno uniti. Solo i file già esistenti verranno sovrascritti.
Esempio:
$ cd /data1/home
$ tar cBf - jdoe | (cd /data2/home ; tar xBf -)
Quando l'azione di copia ha esito positivo, è possibile rimuovere l'origine ( rm -rf <source>
). Naturalmente questa non è una mossa esatta: i dati verranno copiati, fino a quando non rimuovi la fonte.
Come opzione puoi essere prolisso (visualizza sullo schermo il file da copiare), con -v: tar cBvf -
c
: creareB
: leggi blocco completo (per pipe letto)v
: verbosof
: file da scriverex
: estratto-
: stdout / stdinsourcefolder
può anche essere *
(per qualsiasi cosa nella cartella corrente)
f -
di tar non è in genere necessaria: l'impostazione predefinita è leggere da stdin / scrivere a stdout.
Ecco una sceneggiatura che ha funzionato per me. Preferisco mv a rsync, quindi uso le soluzioni di Jewel e Jonathan Mayer.
#!/bin/bash
# usage source1 .. sourceN dest
length=$(($#-1))
sources=${@:1:$length}
DEST=$(readlink -f ${!#})
for SRC in $sources; do
pushd $SRC;
find . -type d -exec mkdir -p ${DEST}/{} \;
find . -type f -exec mv {} ${DEST}/{} \;
find . -type d -empty -delete
popd
done
Non è una buona idea usare comandi come cp o rsync. Per file di grandi dimensioni, ci vorrà molto tempo. mv è molto più veloce poiché aggiorna solo gli inode senza copiare fisicamente i file. Un'opzione migliore è usare il file manager del tuo sistema operativo. Per Opensuse, esiste un file manager chiamato Konquerer. Può spostare i file senza copiarli. Ha la funzione "taglia e incolla" come in Windows. Basta selezionare tutte le sottodirectory nella directory A. Fare clic con il tasto destro del mouse e "spostarsi" nella directory B che può contenere sottodirectory con gli stessi nomi. Li unirà. Esistono anche opzioni per sovrascrivere o rinominare i file con lo stesso nome.
mv
viene utilizzato.
Soluzione Python
Dato che non riuscivo a trovare una soluzione preesistente soddisfacente, ho deciso di creare un rapido script Python per raggiungerlo.
In particolare, questo metodo è efficace perché percorre l'albero dei file di origine solo una volta dal basso verso l'alto.
Ti permetterà anche di modificare rapidamente cose come la gestione della sovrascrittura dei file a tuo piacimento.
Uso:
move-merge-dirs src/ dest/
sposterà tutti i contenuti di src/*
in dest/
e src/
scomparirà.
move-unione-dirs
#!/usr/bin/env python3
import argparse
import os
def move_merge_dirs(source_root, dest_root):
for path, dirs, files in os.walk(source_root, topdown=False):
dest_dir = os.path.join(
dest_root,
os.path.relpath(path, source_root)
)
if not os.path.exists(dest_dir):
os.makedirs(dest_dir)
for filename in files:
os.rename(
os.path.join(path, filename),
os.path.join(dest_dir, filename)
)
for dirname in dirs:
os.rmdir(os.path.join(path, dirname))
os.rmdir(source_root)
if __name__ == '__main__':
parser = argparse.ArgumentParser(
description='Move merge src/* into dest. Overwrite existing files.'
)
parser.add_argument('src_dir')
parser.add_argument('dest_dir')
args = parser.parse_args()
move_merge_dirs(args.src_dir, args.dest_dir)
Questo è il comando per spostare file e cartelle in un'altra destinazione:
$ mv /source/path/folder /target/destination/
Ricorda : il mv
comando non funzionerà se la cartella è b̲e̲i̲n̲g m̲e̲r̲ge̲d̲ (cioè un'altra cartella con lo stesso nome esiste già nella destinazione) e il d̲e̲s̲t̲i̲n̲a̲t̲i̲o̲n̲ o̲n̲e̲ i̲s̲ n̲o̲t̲ e̲m̲pt̲y .
mv: impossibile spostare "/ sorgente / percorso / cartella" su "/ destinazione / destinazione / cartella": directory non vuota
Se la cartella di destinazione è vuota, il comando sopra funzionerà correttamente.
Quindi, per unire entrambe le cartelle in ogni caso,
fallo in 2 comandi:
$ cp -rf /source/path/folder /target/destination/
$ rm -rf /source/path/folder
Oppure combina entrambi come comando singolo:
$ cp -rf /source/path/folder /target/destination/ && rm -rf /source/path/folder
mv = sposta
cp = copia
rm = rimuovi-r per directory (cartella)
-f forza l'esecuzione
mv
. Questa risposta sarebbe migliore con una verità più ampia. Linux, BSD e Unix "reale", o un riferimento da POSIX o SUS.