Jak różnicować wiele plików między katalogami?

19

Próbuję znaleźć diffs między wszystkimi plikami o tych samych nazwach w dwóch kopiach katalogu (powiedzmy działającą i kopię zapasową). Na przykład mogę w diffobu plikach o tej samej nazwie:

> diff d1/f.cpp d2/f.cpp

lub mogę znaleźć różnice między katalogami:

> diff d1 d2

ale jak mogę znaleźć różnice tylko między *.cppplikami?

> diff d1/*.cpp d2/*.cpp

wydaje się nie działać (z oczywistych powodów).

[Prawdopodobnie łatwo go rozwiązać za pomocą pętli, ale staram się znaleźć bardziej elegancki sposób]

tak
źródło

Odpowiedzi:

13

Możesz użyć pętli powłoki, która uruchamia diff dla każdego pliku, chociaż nie złapie to przypadków, w których d2 zawiera plik, ale d1 nie. Może to jednak wystarczyć.

for file in d1/*.cpp; do
    diff "$file" "d2/${file##*/}"
done

Lub wszystkie w jednej linii:

for file in d1/*.cpp; do diff "$file" "d2/${file##*/}"; done

${file##*/}Część jest specjalny parametr ekspansji.

Jeśli zmienna pliku zawiera d1/hello.cpp, to "${file##*/}"rozwinie się do hello.cpp(wartość pliku, ale ze wszystkim, aż do ostatniego / usuniętego).

Tak "d2/${file##*/}"spowoduje d2/hello.cppa polecenie wynikające diff jest zatemdiff d1/hello.cpp d2/hello.cpp

Zobacz http://mywiki.wooledge.org/BashFAQ/100, aby uzyskać więcej informacji na temat manipulacji ciągami w bash.

Na marginesie, system kontroli wersji (taki jak subversion, git, mercurial itp.) Znacznie ułatwiłby tego typu różnicowanie.

geirha
źródło
Myślę, że z dwóch świetnych odpowiedzi, to jest bardziej proste, gdy istnieje wiele typów plików (chociaż wspomniałem w pytaniu, że szukam rozwiązania bez pętli), więc zaakceptowałem to. Dodany dodatek znajduje się echo "${file##*/}";przed diffpoleceniem, więc wiadomo, jakie pliki są faktycznie porównywane. Ponadto, jak wspomniano w odpowiedzi @ Rinzwind, ta metoda nie obejmuje przypadku, w którym lista plików nie jest dokładnie taka sama w obu katalogach.
ysap,
52

diff -qr {DIR1} {DIR2} wykonuje wszystkie pliki w obu katalogach.

  • q pokazuje tylko różnice
  • rrekurencyjne. Zostaw to, jeśli nie jest to potrzebne

Nie możesz powiedzieć diffbezpośrednio, aby używać symboli wieloznacznych, ale możesz dodać:

-x PAT  --exclude=PAT
    Exclude files that match PAT.

-X FILE    --exclude-from=FILE
   Exclude files that match any pattern in FILE.

wykluczać pliki. Więc jeśli chcesz tylko *.cppnajłatwiejszą metodą jest utworzenie pliku tekstowego, który zawiera listę wszystkich plików, które nie są *.cpp. Możesz to zrobić za pomocą następującego polecenia: ls -I "*.cpp" > excluded_filesgdzie -I "*.cpp"argument ignoruje wszystkie pliki .cpp. Pamiętaj, że znaki cudzysłowu są konieczne.

Rinzwind
źródło
Prosty i działa bezbłędnie.
Jose Gómez,
4

Jakiś czas po zadaniu pytania dowiedziałem się o meldnarzędziu diff i od tego czasu go używam. To świetny program oparty na GUI, który sprawia, że ​​porównywanie i łączenie plików i katalogów jest bardzo łatwym zadaniem. Porównuje dwu- lub trójdrożnie.

W szczególności odpowiada na moje pierwotne pytanie, ponieważ pokazuje kolorowe porównanie zawartości katalogu i pozwala porównać określone pliki poprzez dwukrotne kliknięcie nazwy pliku.

Jeśli ktoś potrzebuje więcej niż trójstronnego porównania, to gvimdiff(w oparciu o vimedytor) również jest świetny, który zapewnia tę funkcjonalność.

tak
źródło
1

Jest na to lekkie rozwiązanie:

  1. Skonfiguruj tę niewielką wtyczkę http://www.vim.org/scripts/script.php?script_id=5309
  2. Zrób diff dir1 dir2 | vim -R -w muszli

Dodanie foldów i porównanie obok siebie dla zmienionych plików.

Jurij Erszow
źródło