rsync porównać katalogi?

63

Czy można porównać dwa katalogi z rsync i wydrukować tylko różnice? Istnieje opcja uruchamiania na sucho, ale kiedy zwiększę gadatliwość do pewnego poziomu, pokazywany jest każdy porównywany plik.

ls -alRi diffnie ma tu opcji, ponieważ w źródle znajdują się dowiązania twarde, dzięki czemu każda linia jest inna. (Oczywiście, mogłem usunąć tę kolumnę za pomocą perla.)

Chris
źródło

Odpowiedzi:

46

Prawdopodobnie będziesz musiał przebiec rsync -avun --deletew obu kierunkach.

Ale co tak naprawdę próbujesz osiągnąć?

Aktualizacja :

rsync -avun --delete $TARGET $SOURCE |grep "^deleting " da ci listę plików, które nie istnieją w katalogu docelowym.

"grep delet", ponieważ każdy odbitek linii: delet ing ..file ..

rsync -avun $SOURCE $TARGET da ci listę „różnych” plików (w tym nowych plików).

Nils
źródło
49

Aby dodać do odpowiedzi Nilsa (dla każdego, kto natknie się na to za pośrednictwem Google), domyślnie rsyncporównuje tylko rozmiary plików i czasy modyfikacji, aby stwierdzić, czy są jakieś różnice. (Jeśli są różne, robi więcej, ale jeśli są takie same, zatrzymuje się na tym).

Jeśli chcesz porównać rzeczywistą zawartość pliku , nawet w przypadku plików o tym samym rozmiarze i czasie ostatniej modyfikacji, dodaj flagę, -caby powiedzieć, rsyncaby porównać pliki przy użyciu sumy kontrolnej.

rsync -avnc $SOURCE $TARGET

(Ta -uopcja mówi rsync, aby ignorowało pliki, które są nowsze $TARGETniż te $SOURCE, których prawdopodobnie nie chcesz, jeśli porównujesz zawartość.)

użytkownik98393
źródło
6
Jeśli zależy ci tylko na tym, że dane są takie same, możesz chcieć je dodać --no-group --no-owner --no-perms --no-timeslub ich kombinację w zależności od potrzeb.
flungo
1
@flungo, lub po prostu użyj podzbioru opcji sugerowanych przez -azamiast -a, np.rsync -rlDcnv --delete $SOURCE $TARGET
maxschlepzig
Dodaj --deletedo listy pliki istniejące tylko w$TARGET
Tom Hale
25

Tylko dla osób mniej obeznanych z rsync:

rsync -rvnc --delete ${SOURCE}/ ${DEST}
  • -n: najważniejszy bit - niczego nie zmieniaj;
  • -rc: porównaj tylko zawartość (w przeciwnym razie użyj -ac);
  • -v : lista plików)
  • --delete : szukaj symetrycznej, a nie jednokierunkowej różnicy.
  • Wreszcie /oznacza „zajrzyj do katalogu i porównaj jego zawartość z miejscem docelowym”.

Wydrukuje zwykłe rsyncwyjście,

  • z jednym <nazwa pliku> w wierszu dla każdego „nowego” pliku w${SOURCE}
  • i jeden wiersz „usuwanie <nazwa_pliku>” dla każdego „nowego” pliku w ${DEST}.

  • Może także wydrukować kilka ostrzeżeń, takich jak „pomijanie nieregularnego pliku <nazwa pliku>” dla dowiązań symbolicznych.

PS. Wiem, że to okropne PS - ale rzeczywiście zostało dodane w pośpiechu. Niemniej jednak założę się, że może się to przydać.


PPS. Alternatywnie można również zrobić

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

Jeśli nazwy plików nie zawierają nowych linii, możemy następnie posortować oba *.md5pliki i diffje. (Będzie to jednak działać tylko w przypadku plików; to znaczy, że pusty katalog po obu stronach nie zostanie wykryty).

ジ ョ ー ジ
źródło
15

Zaskakująco żadna odpowiedź od 6 lat nie korzysta z tej -iopcji lub daje niezły wynik, więc zacznę:

TLDR - Po prostu pokaż mi polecenia

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 /'

Zrozumienie wyników

Oto przykład wyniku:

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

Zwróć uwagę na pierwszy znak każdej linii:

  • L/ Roznacza, że ​​plik / katalog pojawia się tylko w katalogu Left lub Right.
  • XOznacza to, że po obu stronach pojawia się plik, ale to nie to samo (w tym przypadku kolejne 11 znaków daje więcej info. s, ta pobrazują różnice w ów ize, t ime i p ermissions odpowiednio - aby uzyskać więcej informacji próbować man rsynci szukać --itemize-changes) .

Dodatkowe opcje, których możesz chcieć użyć

Jeśli chcesz również porównać właściciela / grupę / uprawnienia do plików, dodaj odpowiednio opcje -o/ -g/ -p. Na koniec zauważ, że domyślnie rsync uważa dwa pliki za takie same, jeśli mają tę samą nazwę, godzinę i rozmiar. Jest to niezwykle szybkie i przez większość czasu więcej niż wystarczające, ale jeśli chcesz być w 100% pewien, dodaj -crównież porównaj zawartość plików o tej samej nazwie, czasie i rozmiarze.

TLDR - Po prostu daj mi skrypt do wywołania

Oto jest Nazwij to tak

diff-dirs Left_Dir Right_Dir [options]

Obowiązują tu również wszystkie opcje wymienione powyżej w sekcji „Opcje dodatkowe, których możesz chcieć użyć”.

#!/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 /'

Jak to działa?

Nazywamy rsync w ten sposób:

rsync -rin ...

Używamy -i( --itemize-changes), aby powiedzieć rsync, aby wypisała jeden wiersz danych wyjściowych dla każdego pliku zawierającego informacje o różnicach między dwoma katalogami. Musimy -nstłumić normalne zachowanie rsync (który polega na próbie synchronizacji dwóch katalogów poprzez kopiowanie / usuwanie plików). musimy również -rpracować rekurencyjnie dla wszystkich plików / podkatalogów.

Nazywamy rsync trzy razy:

Pierwsze połączenie : drukuj pliki, które nie istnieją w Dir_B. Musimy użyć, --ignore-existingaby zignorować pliki istniejące po obu stronach.

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

Drugie połączenie : Dokładnie jak poprzednio, ale zamieniamy kolejność DIR_A / DIR_B.

Trzecie połączenie : Wreszcie używamy --existingtylko do sprawdzania plików, które pojawiają się w obu katalogach.

rsync -rin --existing $DIR_A/ $DIR_B/
ndemou
źródło
Nie wiem o innych, ale używam twojego skryptu. Świetna robota! dzięki
Marinaio
7

Rozumiem z twojego pytania, że ​​nie chcesz używać diff na ls , ale możesz także używać diff rekurencyjnie na katalogach:

diff -rq DIR1 DIR2
Camion
źródło
2

Zajęło mi kilka prób, aby to zadziałało. Odpowiedź Nilsa musi $TARGETkończyć się końcem /, jak wyjaśniono w ジ ョ ー ジ.

Oto wersja, która wyraźnie dodaje końcowe /:

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

Daje to listę plików, które istnieją poniżej ${SOURCE}katalogu, ale nie poniżej ${TARGET}katalogu.

Używam sedtutaj, aby usunąć wiodące deletinglinie wyjściowe i wydrukować tylko te linie.

Nie używam tej rsyncopcji, -cponieważ porównywanie zawartości plików byłoby znacznie wolniejsze w moich przypadkach użycia, a porównywanie tylko rozmiarów plików i czasów modyfikacji wydaje się w tych przypadkach wystarczające. Nie mam powodu podejrzewać, że na moich komputerach występują problemy z przesunięciem zegara lub że coś złośliwie zmieniło znaczniki czasu. Ponadto wynik -cnie może zmienić decyzji o usunięciu pliku, a jedynie decyzję o aktualizacji lub zachowaniu pliku.

Używam również -ui -a(zamiast -r), dzięki czemu mogę później ponownie użyć wiersza polecenia i zmienić go skopiować wybrane pliki z katalogów i ${SOURCE}aby ${TARGET}w ten sposób:

rsync -avu ${SOURCE}/{dirA,dirB,fileX} ${TARGET}   # copy some files
Orafu
źródło
0

Mam inny pomysł na zrobienie tego:

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

Możesz dopasować „FILEDETAIL ::” do wyniku polecenia. Możesz także zmienić ciąg „FILEDETAIL ::”. „% N” to nazwa pliku.

-r To mówi rsync, aby rekurencyjnie kopiowało katalogi.

-n To powoduje, że rsync wykonuje test, który nie wprowadza żadnych zmian.

zhao Tony
źródło