rsync confronta le directory?


63

È possibile confrontare due directory con rsync e stampare solo le differenze? C'è un'opzione dry-run, ma quando aumento la verbosità a un certo livello, viene mostrato ogni file confrontato.

ls -alRe diffnon è un'opzione qui, dal momento che ci sono collegamenti fissi nella fonte che rendono ogni riga diversa. (Certo, potrei cancellare questa colonna con perl.)


Risposte:


46

Probabilmente dovrai correre qualcosa del genere rsync -avun --deletein entrambe le direzioni.

Ma cosa stai effettivamente cercando di realizzare?

Aggiornamento :

rsync -avun --delete $TARGET $SOURCE |grep "^deleting " ti darà un elenco di file che non esistono nella directory di destinazione.

"grep delet" perché ogni riga stampa: elimina ing ..file ..

rsync -avun $SOURCE $TARGET ti fornirà un elenco di file "diversi" (inclusi i nuovi file).


49

Per aggiungere alla risposta di Nils (per chiunque si imbatta in questo tramite Google), per impostazione predefinita rsyncconfronta solo le dimensioni del file e i tempi di modifica per dire se ci sono differenze. (Se quelli sono diversi, fa di più, ma se sono uguali, si ferma qui.)

Se si desidera confrontare il contenuto effettivo dei file , anche per file che hanno le stesse dimensioni e il tempo dell'ultima modifica, aggiungere il flag -cper indicare rsyncdi confrontare i file usando un checksum.

rsync -avnc $SOURCE $TARGET

(L' -uopzione dice a rsync di ignorare i file più recenti $TARGETrispetto a quelli attivi $SOURCE, che probabilmente non si desidera se si confrontano i contenuti.)


6
Se ti interessa solo che i dati siano gli stessi, potresti voler aggiungere --no-group --no-owner --no-perms --no-timeso una combinazione di questi in base alle tue esigenze.
flungo,

1
@flungo, o semplicemente usa un sottoinsieme delle opzioni implicite al -aposto di -a, ad esempiorsync -rlDcnv --delete $SOURCE $TARGET
maxschlepzig

Aggiungi --deleteall'elenco i file presenti solo in$TARGET
Tom Hale,

25

Solo per chi ha meno familiarità con rsync:

rsync -rvnc --delete ${SOURCE}/ ${DEST}
  • -n: bit più importante - non modificare nulla;
  • -rc: confronta solo i contenuti (altrimenti usa -ac);
  • -v : elenca i file)
  • --delete : cerca una differenza simmetrica, non unidirezionale.
  • Infine, /significa "cerca nella directory e confronta i suoi contenuti con la destinazione".

Stampa un normale rsyncoutput,

  • con un <nomefile> su una riga per ogni "nuovo" file in${SOURCE}
  • e una riga "eliminazione <nomefile>" per ogni "nuovo" file in ${DEST}.

  • Può anche stampare alcuni avvisi, come "saltare il file non normale <nomefile>" per i collegamenti simbolici.

PS. So che è un terribile PS - ma è stato davvero aggiunto in fretta. Tuttavia, scommetto che uno potrebbe trovarlo utile.


PPS. In alternativa, si potrebbe anche fare

find $SOURCE -type f -exec md5sum {} \; | tee source.md5
find $DEST   -type f -exec md5sum {} \; | tee dest.md5

Se i nomi dei file non contengono newline, possiamo quindi ordinare entrambi i *.md5file e diffquelli. (Questo funzionerà solo per i file; tuttavia, non verrà rilevata una directory vuota su entrambi i lati.)


16

Sorprendentemente nessuna risposta in 6 anni usa l' -iopzione o dà un buon risultato quindi qui andrò:

TLDR - Fammi vedere i comandi

rsync -rin --ignore-existing "$LEFT_DIR"/ "$RIGHT_DIR"/|sed -e 's/^[^ ]* /L             /'
rsync -rin --ignore-existing "$RIGHT_DIR"/ "$LEFT_DIR"/|sed -e 's/^[^ ]* /R             /'
rsync -rin --existing "$LEFT_DIR"/ "$RIGHT_DIR"/|sed -e 's/^/X /'

Comprensione dell'output

Ecco un esempio dell'output:

L             file-only-in-Left-dir
R             file-only-in-right-dir
X >f.st...... file-with-dif-size-and-time
X .f...p..... file-with-dif-perms

Nota il primo carattere di ogni riga:

  • L/ Rsignifica che il file / dir appare solo alla dir Left o Right.
  • Xsignifica che il file viene visualizzato su entrambi i lati, ma non è la stessa (nel qual caso i prossimi 11 caratteri che danno più informazioni. s, te praffigurano le differenze di s ize, t ime e p ermissions rispettivamente - per ulteriori informazioni provare man rsynce cercare --itemize-changes) .

Opzioni extra che potresti voler usare

Se si desidera confrontare anche il proprietario / gruppo / autorizzazioni dei file, aggiungere le opzioni -o/ -g/ -prispettivamente. Infine, nota che per impostazione predefinita rsync considera due file uguali se hanno lo stesso nome, tempo e dimensioni. Questo è estremamente veloce e la maggior parte delle volte più che sufficiente, ma se vuoi essere sicuro -cal 100% aggiungi per confrontare anche il contenuto dei file con lo stesso nome, tempo e dimensioni.

TLDR - Dammi solo uno script da chiamare

Ecco qui. Chiamalo così

diff-dirs Left_Dir Right_Dir [options]

Tutte le opzioni sopra menzionate nella sezione "Opzioni extra che potresti voler usare" si applicano anche qui.

#!/bin/bash
# Compare two directories using rsync and print the differences
# CAUTION: options MUST appear after the directories
#
# SYNTAX
#---------
# diff-dirs Left_Dir Right_Dir [options]
#
# EXAMPLE OF OUTPUT
#------------------
# L             file-only-in-Left-dir
# R             file-only-in-right-dir
# X >f.st...... file-with-dif-size-and-time
# X .f...p..... file-with-dif-perms
#
# L / R mean that the file/dir appears only at the `L`eft or `R`ight dir. 
#
# X     means that a file appears on both sides but is not the same (in which
#       case the next 11 characters give you more info. In most cases knowing
#       that s,t,T and p depict differences in Size, Time and Permissions 
#       is enough but `man rsync` has more info
#       (look at the --itemize-changes option)
#
# OPTIONS
#---------
# All options are passed to rsync. Here are the most useful for the purpose
# of directory comparisons:
#
# -c will force comparison of file contents (otherwise only
#    time & size is compared which is much faster)
#
# -p/-o/-g will force comparison of permissions/owner/group

if [[ -z $2 ]] ; then
    echo "USAGE: $0 dir1 dir2 [optional rsync arguments]"
    exit 1
fi

set -e

LEFT_DIR=$1; shift
RIGHT_DIR=$1; shift
OPTIONS="$*"

# Files that don't exist in Right_Dir
rsync $OPTIONS -rin --ignore-existing "$LEFT_DIR"/ "$RIGHT_DIR"/|sed -e 's/^[^ ]* /L             /'
# Files that don't exist in Left_Dir
rsync $OPTIONS -rin --ignore-existing "$RIGHT_DIR"/ "$LEFT_DIR"/|sed -e 's/^[^ ]* /R             /'
# Files that exist in both dirs but have differences
rsync $OPTIONS -rin --existing "$LEFT_DIR"/ "$RIGHT_DIR"/|sed -e 's/^/X /'

Come funziona?

Chiamiamo rsync in questo modo:

rsync -rin ...

Usiamo -i( --itemize-changes) per dire a rsync di stampare una riga di output per ogni file che contiene informazioni su eventuali differenze tra le due directory. Dobbiamo -nsopprimere il normale comportamento di rsync (che è quello di provare a sincronizzare le due directory copiando / eliminando i file). dobbiamo anche -rlavorare in modo ricorsivo per tutti i file / sottodirectory.

Chiamiamo rsync tre volte:

1a chiamata : stampa file che non esistono in Dir_B. Dobbiamo usare --ignore-existingper ignorare i file che esistono su entrambi i lati.

rsync -rin --ignore-existing $DIR_A/ $DIR_B/

2a chiamata : esattamente come prima ma scambiamo l'ordine di DIR_A / DIR_B.

3a chiamata : infine usiamo --existingsolo per controllare i file che appaiono in entrambe le directory.

rsync -rin --existing $DIR_A/ $DIR_B/

Non conosco gli altri, ma sto usando la tua sceneggiatura. Ottimo lavoro! grazie
Marinaio il

Grazie mille! Avevo bisogno di alcune modifiche, le condividerò di seguito nel caso in cui qualcuno stia cercando qualcosa di simile. Innanzitutto, volevo eseguire rsync remoto come utente sudo, per questo ho aggiunto --rsync-path="sudo rsync"ogni comando rsync. In secondo luogo, volevo confrontare la directory locale con la directory remota. Ho aggiunto --rsh "ssh -p1234"perché nel mio caso SSH è in esecuzione sulla porta 1234. Quindi ho chiamato script come diff-dirs user@111.11.1.1:/mnt/Vol1/dir1/ /localMnt/dir1 -c.
sen4ik

7

Capisco dalla tua domanda che non vuoi usare diff su ls , ma puoi anche usare diff ricorsivamente su directory:

diff -rq DIR1 DIR2

2

Mi ci sono voluti alcuni tentativi per farlo funzionare. La risposta di Nils richiede che $TARGETfinisca in un finale /, come spiegato da ジ ョ ー ジ.

Ecco una versione che aggiunge esplicitamente il trailing /:

rsync -avun --delete ${TARGET}/ ${SOURCE}  | sed -ne 's/^deleting *//p'

Questo fornisce l'elenco dei file che esistono sotto la ${SOURCE}directory ma non sotto la ${TARGET}directory.

Uso sedqui per rimuovere il lead deletingdalle righe di output e per stampare solo quelle righe.

Non uso l' rsyncopzione -cperché il confronto dei contenuti dei file sarebbe molto più lento per i miei casi d'uso e anche in questi casi sembra sufficiente confrontare solo le dimensioni dei file e i tempi di modifica. Non ho motivo di sospettare che i miei computer soffrano di problemi di inclinazione dell'orologio o che qualcosa abbia cambiato in modo pericoloso i timestamp. Inoltre, il risultato di -cnon può cambiare la decisione di eliminare un file, ma solo la decisione di aggiornare o conservare un file.

Uso anche -ue -a(piuttosto che -r), in modo da poter successivamente riutilizzare la riga di comando e modificarla per copiare directory e file selezionati da ${SOURCE}in ${TARGET}, in questo modo:

rsync -avu ${SOURCE}/{dirA,dirB,fileX} ${TARGET}   # copy some files

0

Ho un'altra idea di farlo:

rsync -rn --out-format=FILEDETAIL::%n  $TARGET $SOURCE  | grep "^FILEDETAIL"

È possibile associare "FILEDETAIL ::" all'output del comando. Inoltre, è possibile modificare la stringa "FILEDETAIL ::". "% N" è il nome del file.

-r Questo dice a rsync di copiare ricorsivamente le directory.

-n Questo fa in modo che rsync esegua una corsa di prova che non apporta alcuna modifica.

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.