cartelle di unione di linux: rsync?


13

Ho due copie di una cartella

src/
dest/

Voglio unirli, facendo quanto segue:

Se un file è solo in src, voglio che sia spostato indest

Se un file è solo in dest, voglio che IE ignorato rimanga solo.

Se un file è in entrambi e ha contenuti identici (IE stessa dimensione e data), elimina dasrc

Se un file si trova in entrambi e non ha contenuti identici, lasciarlo indietro srccosì posso unirli manualmente.

Solo un numero molto piccolo di file (tra lo 0% e il 5% del totale dei file) dovrebbe essere in quest'ultima categoria, ma non so come separare l'uno in entrambi e lo stesso da entrambi, ma diverso.

Ho provato a capire come farlo rsyncma senza risultati finora.

Risposte:


17

Ho eseguito solo test di funzionalità limitati, quindi fai attenzione con questo comando (--dry-run):

rsync -avPr --ignore-existing --remove-source-files src/ dest

Si prega di notare il trascinamento / poiché questo si ripeterà in src invece di copiare src stesso, questo dovrebbe mantenere i percorsi esistenti.

Usando il flag --ignore-esistente in combinazione con il flag --remove-source-files, cancellerai solo i file da src che sono sincronizzati da src a dest, ovvero file che prima non esistevano solo in dest.

Per eliminare file non sincronizzati, ovvero quelli già esistenti in dest / come in src /, è possibile utilizzare:

for file in `find src/ -type f`; do diff $file `echo $file | sed 's/src/dest/'` && rm $file || echo $file; done

o

find src -type f -exec bash -c 'cmp -s "$0" "${0/#src/dest}" && rm "$0"' {} \;

se i nomi dei file potrebbero contenere spazi bianchi / nuove righe / ... Per quanto riguarda il commento di Gilles su caratteri speciali, questo è certamente qualcosa di cui tenere conto e ci sono molte soluzioni, il più semplice sarebbe passare un -i a rm che chiederà prima di ogni cancellazione. A condizione che sia fornito src /, o il suo percorso genitore, per trovare, tuttavia, il percorso completo dovrebbe comportare la corretta gestione di tutti i nomi file sia dai comandi diff che rm senza virgolette.


correzione: quel comando non rimuoverà i file da src se esiste già una copia identica in dest
Tok

Sì :(. Questa è la parte che trovo difficile da capire.
David Oneill

2
Bene, la buona notizia è che puoi risolverlo in modo indipendente senza troppe seccature: for file in `find src/ -type f`; do diff $file `echo $file | sed 's/src/dest/'` && rm $file || echo $file; done(puoi saltare il, || echo $filese vuoi, è incluso per completezza)
Tok

Nifty: questo è quello di cui avevo bisogno. Modificalo nella tua risposta e lo accetterò!
David Oneill,

@Tok: il tuo comando si strozzerà con nomi di file che contengono caratteri speciali (spazi bianchi \?*[, iniziale -). È necessario utilizzare le virgolette doppie attorno alle sostituzioni variabili , passare --alle utility prima dei nomi dei file, utilizzare find … -exec …invece di analizzare l'output di find. Con un rmcomando nel mix, questa è una ricetta per il disastro.
Gilles 'SO- smetti di essere malvagio' il

6

all'unisono è lo strumento che stai cercando. Prova unison-gtk se preferisci una gui. Ma non credo che cancellerà file simili: all'unisono si tenta di avere entrambe le directory identiche. Tuttavia, sarà facile 1) identificare quali file devono essere copiati; 2) quali richiedono l'unione manuale.


Non fa esattamente ciò che richiede l'OP, ma sembra che raggiunga l'obiettivo finale dell'OP. +1
Ryan C. Thompson,

+1 Purtroppo, sul server sul quale sto eseguendo non è installato all'unisono, né ho i permessi per installarlo. Ma questa potrebbe essere una buona risposta a qualcun altro.
David Oneill,

1
Puoi scaricare un eseguibile all'unisono da seas.upenn.edu/~bcpierce/unison//download/… . Installalo da qualche parte nella tua home directory, è solo un file.
JooMing,

2

Il seguente script dovrebbe fare le cose ragionevolmente. Sposta i file dalla sorgente alla destinazione, non sovrascrivendo mai un file e creando directory se necessario. I file di origine che hanno un file diverso corrispondente nella destinazione vengono lasciati soli, così come i file che non sono file o directory regolari (ad esempio collegamenti simbolici). I file rimasti nel sorgente sono quelli per i quali esiste un conflitto. Attenzione, non l'ho provato affatto.

cd src
find . -exec sh -c '
    set -- "/path/to/dest/$0"
    if [ -d "$0" ]; then #  the source is a directory 
      if ! [ -e "$1" ]; then
        mv -- "$0" "$1"  # move whole directory in one go
      fi
    elif ! [ -e "$0" ]; then  # the source doesn't exist after all
      :  # might happen if a whole directory was moved
    elif ! [ -e "$1" ]; then  # the destination doesn't exist
      mv -- "$0" "$1"
    elif [ -f "$1" ] && cmp -s -- "$0" "$1"; then  # identical files
      rm -- "$0"
    fi
  ' {} \;

Un altro approccio sarebbe quello di fare una mount mount una directory sopra l'altra, ad esempio con funionfs o unionfs -fuse .

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.