Linux: Porównaj strukturę katalogów bez porównywania plików

55

Jaki jest najlepszy i najprostszy sposób porównania dwóch struktur katalogów bez faktycznego porównywania danych w plikach? Działa to dobrze:

diff -qr dir1 dir2_

Ale jest bardzo powolny, ponieważ porównuje również pliki. Czy jest do tego dostępny przełącznik diff lub inne proste narzędzie cli?

Jonasz
źródło
Czy przez „strukturę katalogów” rozumiesz tylko ścieżki katalogów, czy ścieżki zarówno plików katalogowych, jak i plików innych niż katalogowe?
intuicyjnie
Tak, foldery i pliki.
Jonah
1
W takim przypadku należy usunąć -type dopcję z odpowiedzi @ slartibartfast lub sprawdzić moją odpowiedź.
intuicyjnie

Odpowiedzi:

36

Następujące czynności (jeśli podstawisz pierwszy katalog na katalog1, a drugi na katalog2), powinny zrobić to, czego szukasz i szybko:

find directory1 -type d -printf "%P\n" | sort > file1
find directory2 -type d -printf "%P\n" | sort | diff - file1

Podstawową zasadą jest to, że drukuje wszystkie katalogi, w tym ścieżki podkatalogów względem katalogu bazowego kataloguN.

Może to upaść (produkować dziwne dane wyjściowe), jeśli masz zwroty karetki w niektórych nazwach katalogów, ale nie w innych.

Slartibartfast
źródło
Nie jest to dla mnie dobre, ponieważ jeśli jeden katalog zawiera folder z kilkoma tysiącami plików, wszystkie są wymienione osobno, podczas gdy diff -rqtylko pokazuje katalog główny istnieje w jednym i kontynuuje.
Chris Jefferson
Jak wskazano (lata temu) intuicyjnie, aby odpowiedzieć na pytanie PO, należy usunąć typ-d, aby pliki były uwzględniane w porównaniu, a także w katalogach
2746401
Rozumiem i szanuję tę lekturę opisu problemu. To nie było wtedy moje czytanie. Czy zalecasz edycję mojej odpowiedzi, aby odpowiedzieć na zaktualizowane pytanie? Mogę to zrobić, jeśli uważasz, że będzie to pomocne dla niektórych osób, i mogę pozostawić rozwiązanie i komentarz tak, jak są teraz, co wydaje się dość skuteczne.
Slartibartfast
34
vimdiff <(cd dir1; find . | sort) <(cd dir2; find . | sort)

da Ci przyjemne wyświetlanie obok siebie dwóch hierarchii katalogów ze złożonymi wszystkimi popularnymi sekcjami.

garyjohn
źródło
To rozwiązanie zawiesza się losowo. Kiedy vim czyta (lub ponownie czyta) tymczasowy deskryptor pliku, już go nie ma.
Denilson Sá Maia,
23

Zwykle używam rsyncdo tego zadania:

rsync -nav --delete DIR1/ DIR2

BĄDŹ BARDZO OSTROŻNY, aby zawsze używać opcji-naka--dry-run, ponieważ spowoduje to synchronizację (zmianę zawartości) katalogów.

Spowoduje to porównanie plików na podstawie czasów i rozmiarów modyfikacji plików ... Myślę , że tego naprawdę chcesz, a przynajmniej nie masz nic przeciwko, jeśli to zrobi? Mam wrażenie, że po prostu chcesz, aby stało się to szybciej , a nie że musisz ignorować różnicę między zawartością pliku. Jeśli chcesz, aby nie wyświetlał różnych plików o identycznych nazwach, myślę, że dodanie tej --ignore-existingopcji to zrobi.

Również należy pamiętać, że nie wstawiając /na końcu DIR1spowoduje to porównanie katalogu DIR1 z zawartością o DIR2.

Dane wyjściowe są nieco szczegółowe, ale pokażą, które pliki / katalogi różnią się. Pliki / katalogi obecne w, DIR2a nie w, DIR1będą poprzedzone słowem deleting.

W niektórych sytuacjach odpowiedź @ slartibartfast może być bardziej odpowiednia, chociaż musisz usunąć -type dopcję, aby włączyć wyświetlanie plików spoza katalogu. rsyncbędzie szybszy, jeśli masz znaczną liczbę plików / katalogów do porównania.

intuicyjny
źródło
Doskonała odpowiedź. W wynikach rsync trudno jest zauważyć deleting...tekst, ale prawdopodobnie jest to jeden z lepszych sposobów porównywania plików przy jednoczesnym zachowaniu szybkości. Inne odpowiedzi tutaj są szybsze, gdy różnicowanie plików nie jest wymagane ... jak w przykładzie OP, ale naprawdę podoba mi się ten.
Joel Mellon,
Tego właśnie szukałem. Miałem kilka plików o różnych rozmiarach w ogromnej parze drzew katalogów i chciałem wiedzieć, które. Osiągnął ten cel w zaledwie kilka sekund.
suprjami
Być może dobrym pomysłem jest uruchomienie go z użytkownikiem, który ma dostęp tylko do odczytu. Tak jak sudo -u nobody rsync -nav --delete d1 d2pod warunkiem, że flagi dla „innych” pozwalają na czytanie.
user1182474
Podczas uruchamiania tego rozwiązania otrzymałem „tworzenie listy plików ... zrobione \ n wysłane X bajtów odebranych Y bajtów Z bajtów Z / s całkowity rozmiar to Przyspieszenie B” (gdzie podstawiłem XYZAB na liczby). Czy to oznacza, że ​​wszystko było identyczne? Skoro nie wspomniał o niczym bardziej szczegółowym? Z góry dziękuję
Scott H
Aby odpowiedzieć na moje pytanie, eksperymentowałem z dodawaniem różnych plików do każdego z nich i wydaje się, że żadne konkretne pliki / katalogi wymienione w danych wyjściowych nie oznaczają, że wszystkie są takie same.
Scott H
18

Podobne do odpowiedzi ls, ale jeśli zainstalujesz drzewo , możesz

tree dir1 > out1
tree dir2 > out2
diff out1 out2
cyfra
źródło
7
Lub, aby uniknąć plików tmp,diff <( tree dir1 ) <( tree dir2 )
Joel Mellon,
1
Polecam uruchomienie drzewa z iflagą, która nie drukuje linii drzewa ( tree -i dir1itp.). Jeśli struktura katalogów jest inna w jednym miejscu, inne pasujące pliki mogą mieć więcej lub mniej |symboli w danych wyjściowych drzewa, a diff przechwyci te linie, nawet jeśli ścieżki plików są identyczne.
askewchan,
2
diff <(drzewo -i katalog1) <(drzewo -i katalog2) jest zdecydowanie najlepszą odpowiedzią. Kusi mnie, by zanegować wszystkie odpowiedzi sugerujące diff lub rsync, ponieważ pytanie wyraźnie mówi NIE czytać zawartości pliku. UWAGA: Sugestia użycia dwóch rur wymaga starannego wykorzystania odstępów między nawiasami, podążaj dokładnie za przykładem. Np. Aby porównać dwa woluminy 20G po utworzeniu kopii zapasowej, odpowiedź drzewa zajęła około 5 sekund. Pozostali zajęli ponad 20 minut.
Jason Morgan
3

Po prostu szukałem rozwiązania tego problemu. Najbardziej podobało mi się:

comm <(ls DIR1) <(ls DIR2)

Daje ci 3 kolumny: 1 - pliki tylko w DIR1, 2 - pliki tylko w DIR2, 3 - pliki tylko w DIR3 Aby uzyskać więcej informacji, zobacz ten post na blogu.

kyrisu
źródło
Gdzie jest DIR3określony? Widzę tylko DIR1i DIR2.
Michael Dorst,
Próbowałem go i (z tego co mogę powiedzieć) wyjście było: wszystkie pliki tylko DIR1w kolumnie 1 , wszystkie pliki tylko w DIR2w kolumnie 2 , a wszystkie pliki udostępnione przez zarówno w kolumnie 3 . To trochę użyteczne, ale czy wiesz, jak można usunąć kolumnę 3 i pozostawić tylko różnice? Mam wiele plików do posortowania, a większość z nich jest identyczna. Nie muszę widzieć, co jest takie samo.
Michael Dorst,
1
Odkryłem też, że comm <(ls DIR1) <(ls DIR2)nie działa rekurencyjnie. Do tego użyłem comm <(ls -R1 DIR1) <(ls -R1 DIR2). ls -Rprzeszukuje katalogi rekurencyjnie i ls -1(zauważ, że to jest jeden , a nie L ) sprawia, że lsdrukuje tylko jedną nazwę pliku w linii.
Michael Dorst,
@Michael: comm -3(patrz man comm).
Zaz
2
ls > dir1.txt

ls > dir2.txt

Następnie różnicuj dwie listy.

MDMarra
źródło
Wygląda na to, że OP chce heirarchii ścieżek. Spowoduje to różnicowanie wszystkich plików w bieżącym katalogu. Jest dyskusyjne, ale możliwe, że chce tylko katalogów; mógłby chcieć nazw plików zamiast zawartości plików.
intuicyjnie
@intuited - masz rację. Źle to odczytałem.
MDMarra,
2

To optymalne rozwiązanie

diff --brief -r dir1 dir2

- krótki przełącznik informuje tylko, czy pliki się różnią, a nie szczegóły różnicy.

jkshah
źródło
1
OP ma już -qw pytaniu, które jest pseudonimem --brief. Ta odpowiedź nie zawiera żadnych nowych informacji.
Michael Dorst,
1
OP nie chce porównania zawartości pliku. But it's really slow because it's comparing files too.
Joel Mellon,
1

użyj „diff -qr”, aby pobrać różne pliki, a następnie odfiltruj porównanie plików z grep, aby uzyskać tylko nazwy plików, które są tylko w jednym z katalogów.

diff -qr dir1 dir2 | grep -v "Files.*differ" 
Anonimowy
źródło
1

Działa to z moją konkretną potrzebą znalezienia brakujących plików w drzewach, które powinny pasować.

diff <( cd dir1; find * |sort ) <(cd dir2; find * | sort)
amhest
źródło
-3

Myślę, że tylko rsync jest użyteczny. dlaczego?

diff jest użyteczny tylko dla struktur przechowujących pliki i katalogi. Diff nie podaje odpowiednich kodów wyjścia, gdy używamy dowiązań symbolicznych. W takiej sytuacji diff może zwrócić 2 kody wyjścia, nawet jeśli src i dst są identyczne (czasy, rozmiary, nazwy, znaczniki czasu, wskazywanie softlinków itp.).

reż, system plików nie gwarantuje porządkowania plików, nawet jeśli zawartość katalogu na src i dst jest identyczna. Może powinieneś przefiltrować wyjście ls, sortując je. Ale czysty ls wyświetla tylko nazwy węzłów.

być może skrypt zawierający diff, cmp, test -X dla typów węzłów będzie przydatny, ale pamiętaj o przeciążeniu spowodowanym przez wiele testów / cmp. Skrypt będzie bardzo wolny.

Jak zwykle, jeśli chcesz uzyskać proste informacje „katalog jest / nie jest identyczny”, powinieneś użyć rsync z opcją -n (sucha). Jeśli chcesz dowiedzieć się, co jest inne, użyj polecenia diff.

Znik
źródło
Chciałbym wiedzieć, dlaczego minusy?
Znik