Wyprowadzić wspólne linie (podobieństwa) dwóch plików tekstowych (przeciwieństwo diff)?

21

Różnicowanie to świetne narzędzie do wyświetlania zmian między dwoma plikami. Ale jak wyświetlić podobieństwa dwóch plików tekstowych (ignorując różnice)?

Tzn. Przykładowe dane wejściowe:

a:
Foo Bar
X
Hello
World
42

b:
Foo Baz
Hello
World
23

Pseudo wyjście (coś takiego):

@@ 2,3
=Hello World

Samo sortowanie obu plików i używanie komunikatora nie wystarczy, ponieważ w takim przypadku informacje o linii zostaną utracone.

maxschlepzig
źródło

Odpowiedzi:

24

Co powiesz na użycie diff, nawet jeśli nie chcesz diff? Spróbuj tego:

diff --unchanged-group-format='@@ %dn,%df 
  %<' --old-group-format='' --new-group-format='' \
  --changed-group-format='' a.txt b.txt

Oto, co otrzymuję z przykładowymi danymi:

$ cat a.txt 
Foo Bar
X
Hello
World
42
$ cat b.txt 
Foo Baz
Hello
World
23
$ diff --unchanged-group-format='@@ %dn,%df
%<' --old-group-format='' --new-group-format='' \
  --changed-group-format='' a.txt b.txt
@@ 2,3
Hello
World
Mike Gray
źródło
2
Możesz uniknąć osadzania dosłownego nowego wiersza w ten sposób:...%df'$'\n''%<'...
Wstrzymano do odwołania.
1
Możesz to również zrobić w następujący sposób: ... --unchanged-group-format="@@ %dn,%df%c'\012'%<" ...(Uwaga na podwójne cudzysłowy.)
Wstrzymano do odwołania.
Świetna sprawa! Nie znałem tych opcji, ponieważ właśnie spojrzałem na stronę man diff ...
maxschlepzig
Używam diff --version diff (GNU diffutils) 2.8.1 I pojawia się następujący błąd: diff: opcje stylu wyjścia sprzeczne diff: Wypróbuj `diff --help ', aby uzyskać więcej informacji.
Sujay,
Pojawił się komunikat „error: diff: sprzeczne opcje stylu wyjściowego diff”, ponieważ zdefiniowałem alias diff. Użyj, which diffaby sprawdzić, czy to twój problem.
justinjhendrick
14
grep -Fxf file1 file2

-Foznacza dopasowanie zwykłych ciągów (nie wyrażeń regularnych), -xoznacza tylko dopasowania całej linii, -foznacza pobranie „wzorców” (tj. linii) z pliku o nazwie jako argument

tobyodavies
źródło
3
Nie są -fi -Fwymieniane ?. Tak przynajmniej jest w mojej grepwersji. Muszę podać file2dane wejściowe do -fargumentu, jak cat file1 | grep -Fxf file2, a następnie działa.
Birei
To nie zadziałało dla mnie.
Chaminda Bandara
7

commmoże być użyte. man commdla wszystkich opcji, ale będziesz chciał użyć, comm -12 ...aby wyświetlić tylko linie, które istnieją na obu wejściach.

Jak zauważyli ludzie, najpierw musisz przekazać swoje uwagi sort.

Oli
źródło
1
Hm, to działa tylko dla wspólnych linii, które mają ten sam numer linii w obu plikach.
maxschlepzig
2
comm wydaje się być tylko dla posortowanych plików i nie daje tego użytecznego wyjścia dla przypadku użycia OP. Jego przykład: $ comm -12 ab Hello World comm: plik 1 nie jest posortowany comm: plik 2 nie jest posortowany
Marcel Stimberg
@maxschlepzig: powinieneś posortować swoje pliki przed przekazaniem ich do komunikatora.
Hemant,
2
Jednak sortując pozbywasz się wszystkich informacji o położeniu wspólnych linii. Nie posortowałbyś plików przed porównaniem ich z diff.
Marcel Stimberg
7

Nie sądzę, aby istniało jedno polecenie, które robi to, co chcesz. Możesz jednak spróbować połączyć wyjście diffz grep. Jeśli pliki tekstowe zawierają żadnego z bohaterów |, <, >dodaje daje nieco przydatnych wyjście:

$ diff --side-by-side a b | grep -n -v "[|<>]"
3:Hello                             Hello
4:World                             World
Marcel Stimberg
źródło
Spróbuj tego:diff --width=155 --left-column --side-by-side a b | grep -n -v '|' | sed 's/ *($//'
Wstrzymano do odwołania.
wygląda to lepiej - ale musisz wstawić <i> w grep, aby pozbyć się również dodanych linii w obu plikach.
Marcel Stimberg
2

Dick Grune napisał rodzinę narzędzi do tego rodzaju rzeczy:

http://dickgrune.com/Programs/similarity_tester/

Istnieją wersje, które analizują składnię różnych języków, dzięki czemu zmienne o zmienionych nazwach mogą być postrzegane jako niezmienione.

Jest pakowany jak similarity-testerw Debianie i Ubuntu.

Douglas Bagnall
źródło