diff, aby wyświetlać tylko nazwy plików

244

Chcę uruchomić polecenie systemu Linux, które rekurencyjnie porównuje dwa katalogi i wyświetli tylko nazwy plików tego, co jest inne. Obejmuje to wszystko, co jest obecne w jednym katalogu, a nie w drugim lub odwrotnie, oraz różnice w tekście.

barfoon
źródło

Odpowiedzi:

376

Ze strony man diff:

-q   Zgłoś tylko, czy pliki się różnią, a nie szczegóły różnic.
-r   Porównując katalogi, rekurencyjnie porównaj wszystkie znalezione podkatalogi.

Przykładowe polecenie:

diff -qr dir1 dir2

Przykładowe dane wyjściowe (zależy od ustawień regionalnych):

$ ls dir1 dir2
dir1:
same-file  different  only-1

dir2:
same-file  different  only-2
$ diff -qr dir1 dir2
Files dir1/different and dir2/different differ
Only in dir1: only-1
Only in dir2: only-2
John Kugelman
źródło
Dzięki - diffstrona podręcznika w CentOS 7 opisuje -qjako „raportuj tylko wtedy, gdy pliki się różnią”, co jest mniej jasne niż to, co napisałeś.
Rozdział
2
Porównuje to faktyczną zawartość plików, co jest często tym, czego się chce, jednak odpowiedź rsync daje możliwość przeglądania tylko nazw i rozmiarów plików, a nie zawartości; to jest czasem pożądane.
steveb
Działa również na macOS.
Marius Soutier
Może także zawierać -x PATTERNw poleceniu wykluczenie niektórych podkatalogów. Na przykład diff -qr repo1 repo2 -x ".git" porówna dwa katalogi, ale wykluczy ścieżki plików z „.git” w nich.
ViFI
27

Możesz także użyć rsync

rsync -rv --size-only --dry-run /my/source/ /my/dest/ > diff.out
boksiora
źródło
6
--size-onlybędzie brakować plików o identycznym rozmiarze, ale różnej zawartości, np. stary / wersja.txt „29a” nowy / wersja.txt „29b” . Zamiast tego użyj: rsync -ric --dry-run old/ new/gdzie argument „-i” pozwala uzyskać listę plików bezpośrednio przezrsync -ric --dry-run old/ new/ | cut -d" " -f 2
iolsmit
6
Jest to świetne, jeśli szukasz tylko brakujących plików (zwłaszcza między udziałami sieciowymi), ponieważ nie porównuje zawartości. Pomogło mi to znaleźć kilka plików, które uległy awarii podczas migracji na nowy serwer NAS.
OverZealous,
4
Pamiętaj o dołączeniu ukośnika końcowego dla ścieżek określonych w wierszu poleceń rsync. Bez nich to nie będzie działać poprawnie, a rsync prawdopodobnie po prostu wyliczy wszystkie nazwy plików!
Vladimir Panteleev
2
W odniesieniu do komentarzy na temat nie sprawdzania treści. Jest to czasem pożądane, przynajmniej jako pierwsze przejście.
steveb
13

Jeśli chcesz uzyskać listę plików znajdujących się tylko w jednym katalogu, a nie ich podkatalogów i tylko ich nazwy:

diff -q /dir1 /dir2 | grep /dir1 | grep -E "^Only in*" | sed -n 's/[^:]*: //p'

Jeśli chcesz rekurencyjnie wyświetlić listę wszystkich plików i katalogów, które różnią się ich pełnymi ścieżkami:

diff -rq /dir1 /dir2 | grep -E "^Only in /dir1*" | sed -n 's/://p' | awk '{print $3"/"$4}'

W ten sposób możesz zastosować różne polecenia do wszystkich plików.

Na przykład mogę usunąć wszystkie pliki i katalogi znajdujące się w katalogu 1, ale nie w katalogu 2:

diff -rq /dir1 /dir2 | grep -E "^Only in /dir1*" | sed -n 's/://p' | awk '{print $3"/"$4}' xargs -I {} rm -r {}
ND
źródło
9

W moim systemie Linux, aby uzyskać tylko nazwy plików

diff -q /dir1 /dir2|cut -f2 -d' '
gerardw
źródło
7
Nie umieszczam nazw plików ze spacjami w moim systemie Linux. ;)
gerardw
6
Nie chciałem ci tego przypisywać ... ;-p Tylko jako wskazówka dla kogoś, kto to robi ...
michuelnik,
nie działa dla mnie Moja struktura katalogów jest jak poniżejaudit-0.0.234/audit-data-warehouse-0.0.234/ audit-0.0.235/audit-data-warehouse-0.0.235/
Alex Raj Kaliamoorthy
diff -qrN /dir1 /dir2 | cut -f2 -d' 'działa dobrze dla mnie!
Francesco,
9

Podejście do uruchamiania diff -qr old/ new/ma jedną poważną wadę: może brakować plików w nowo utworzonych katalogach. Np. W poniższym przykładzie pliku data/pages/playground/playground.txtnie ma na wyjściu, diff -qr old/ new/podczas gdy katalog data/pages/playground/jest (wyszukaj playground.txt w przeglądarce aby szybko porównać). Opublikowałem również następujące rozwiązanie na giełdzie stosów Unix i Linux , ale skopiuję je również tutaj:

Aby utworzyć listę nowych lub zmodyfikowanych plików programowo najlepszym rozwiązaniem, jakie mogłem wymyślić, jest użycie rsync , sort i uniq :

(rsync -rcn --out-format="%n" old/ new/ && rsync -rcn --out-format="%n" new/ old/) | sort | uniq

Pozwól mi wyjaśnić za pomocą tego przykładu: chcemy porównać dwie wersje dokuwiki, aby zobaczyć, które pliki zostały zmienione, a które nowo utworzone.

Ściągamy smoły za pomocą wget i wyodrębniamy je do katalogów old/inew/ :

wget http://download.dokuwiki.org/src/dokuwiki/dokuwiki-2014-09-29d.tgz
wget http://download.dokuwiki.org/src/dokuwiki/dokuwiki-2014-09-29.tgz
mkdir old && tar xzf dokuwiki-2014-09-29.tgz -C old --strip-components=1
mkdir new && tar xzf dokuwiki-2014-09-29d.tgz -C new --strip-components=1

Uruchamianie rsync w jedną stronę może spowodować pominięcie nowo utworzonych plików, ponieważ porównanie rsync i diff pokazuje tutaj:

rsync -rcn --out-format="%n" old/ new/

daje następujące dane wyjściowe:

VERSION
doku.php
conf/mime.conf
inc/auth.php
inc/lang/no/lang.php
lib/plugins/acl/remote.php
lib/plugins/authplain/auth.php
lib/plugins/usermanager/admin.php

Uruchomienie rsync tylko w jednym kierunku powoduje pominięcie nowo utworzonych plików, a na odwrót pominięcie usuniętych plików, porównanie danych wyjściowych diff:

diff -qr old/ new/

daje następujące dane wyjściowe:

Files old/VERSION and new/VERSION differ
Files old/conf/mime.conf and new/conf/mime.conf differ
Only in new/data/pages: playground
Files old/doku.php and new/doku.php differ
Files old/inc/auth.php and new/inc/auth.php differ
Files old/inc/lang/no/lang.php and new/inc/lang/no/lang.php differ
Files old/lib/plugins/acl/remote.php and new/lib/plugins/acl/remote.php differ
Files old/lib/plugins/authplain/auth.php and new/lib/plugins/authplain/auth.php differ
Files old/lib/plugins/usermanager/admin.php and new/lib/plugins/usermanager/admin.php differ

Uruchomienie rsync na dwa sposoby i sortowanie danych wyjściowych w celu usunięcia duplikatów ujawnia, że ​​katalog data/pages/playground/i plik data/pages/playground/playground.txtzostały początkowo pominięte:

(rsync -rcn --out-format="%n" old/ new/ && rsync -rcn --out-format="%n" new/ old/) | sort | uniq

daje następujące dane wyjściowe:

VERSION
conf/mime.conf
data/pages/playground/
data/pages/playground/playground.txt
doku.php
inc/auth.php
inc/lang/no/lang.php
lib/plugins/acl/remote.php
lib/plugins/authplain/auth.php
lib/plugins/usermanager/admin.php

rsync jest uruchamiany z tymi argumentami:

  • -r „przekierowywać do katalogów”,
  • -c aby porównać również pliki o identycznym rozmiarze i tylko „pomiń na podstawie sumy kontrolnej, a nie czasu i rozmiaru mod”,
  • -n „wykonać jazdę próbną bez zmian”, oraz
  • --out-format="%n" do „wypisywania aktualizacji za pomocą określonego FORMATU”, czyli „% n” tutaj tylko dla nazwy pliku

Dane wyjściowe (lista plików) rsyncw obu kierunkach są łączone i sortowane za pomocą sort, a ta posortowana lista jest następnie zagęszczana poprzez usunięcie wszystkich duplikatów za pomocąuniq

iolsmit
źródło
Czy nie możesz po prostu uruchomić go wstecz ( diff new/ old/), aby zobaczyć, które katalogi zostały usunięte?
Jacques,
Bieganie diff -qr new/ old/na powyższym przykładzie ze smoły dokuwiki produkuje taką samą moc jak diff -qr old/ new/- czyli widać, że katalog jest nowy / brakujące pliki, ale nie w niej
iolsmit
-4
rsync -rvc --delete --size-only --dry-run source dir target dir
mayank
źródło