Wie zeige ich gemeinsame Linien (Reverse Diff)?

170

Ich habe eine Reihe von Textdateien, für die ich lieber die gemeinsamen Zeilen als die zwischen ihnen unterschiedlichen Zeilen kennen möchte. Befehlszeilen-Unix oder Windows ist in Ordnung.

foo:

linux-vdso.so.1 =>  (0x00007fffccffe000)
libvlc.so.2 => /usr/lib/libvlc.so.2 (0x00007f0dc4b0b000)
libvlccore.so.0 => /usr/lib/libvlccore.so.0 (0x00007f0dc483f000)
libc.so.6 => /lib/libc.so.6 (0x00007f0dc44cd000)

Bar:

libkdeui.so.5 => /usr/lib/libkdeui.so.5 (0x00007f716ae22000)
libkio.so.5 => /usr/lib/libkio.so.5 (0x00007f716a96d000)
linux-vdso.so.1 =>  (0x00007fffccffe000)

Angesichts dieser beiden Dateien über der Ausgabe des gewünschten Dienstprogramms wäre dies also vergleichbar file1:line_number, file2:line_number == matching text (nur ein Vorschlag, die Syntax ist mir wirklich egal):

foo:1, bar:3 == linux-vdso.so.1 =>  (0x00007fffccffe000)

Vielen Dank.

matt wilkie
quelle
@ChristopherSchultz Mein Fehler. 1. Zeile im 1. Beispiel soll mit der letzten Zeile im 2. Beispiel übereinstimmen. Vielen Dank, dass Sie den Fehler entdeckt haben. Ändern.
Matt Wilkie
1
Eine andere ähnliche Frage mit guten Antworten: unix.stackexchange.com/questions/1079/…
MortezaE

Antworten:

210

Unter * nix können Sie comm verwenden . Die Antwort auf die Frage lautet:

comm -1 -2 file1.sorted file2.sorted 
# where file1 and file2 are sorted and piped into *.sorted

Hier ist die vollständige Nutzung von comm:

comm [-1] [-2] [-3 ] file1 file2
-1 Suppress the output column of lines unique to file1.
-2 Suppress the output column of lines unique to file2.
-3 Suppress the output column of lines duplicated in file1 and file2. 

Beachten Sie auch, dass es wichtig ist, die Dateien zu sortieren, bevor Sie comm verwenden, wie in den Manpages erwähnt.

Dan Lew
quelle
3
comm [-1] [-2] [-3] file1 file2 -1 Unterdrückt die Ausgabespalte von Zeilen, die nur für file1 gelten. -2 Unterdrücke die Ausgabespalte von Zeilen, die nur für Datei2 gelten. -3 Unterdrücken Sie die Ausgabespalte der in Datei1 und Datei2 duplizierten Zeilen.
Ojblass
@ojblass: Dies wurde der Antwort hinzugefügt.
Matt J
6
Ich habe festgestellt, dass es wichtig ist, die Dateien vor der Verwendung von comm zu sortieren. Vielleicht fügen Sie das der Antwort hinzu.
Matt Wilkie
11
kurze Antwort auf die Frage: comm -1 -2 file1 file2
greggles
6
Sie können dies verwenden, wenn Ihre Dateien nicht sortiert sind: comm -1 -2 <(Dateiname1 sortieren) <(Dateiname sortieren2)
Kevin Wheeler
56

Diese Antwort wurde bei einer Frage gefunden, die als Duplikat aufgeführt ist . Ich finde, dass grep adminfreundlicher ist als comm. Wenn Sie also nur die passenden Zeilen (zum Beispiel zum Vergleichen von CSVs nützlich) verwenden möchten, verwenden Sie einfach

grep -F -x -f file1 file2

oder die vereinfachte fgrep-Version

fgrep -xf file1 file2

Außerdem können Sie file2*nicht nur zwei, sondern mehrere Zeilen gemeinsam mit mehreren Dateien suchen.

Einige andere praktische Variationen sind

  • -n Flag, um die Zeilennummer jeder übereinstimmenden Zeile anzuzeigen
  • -c um nur die Anzahl der übereinstimmenden Zeilen zu zählen
  • -vum nur die Zeilen in Datei2 anzuzeigen , die sich unterscheiden (oder verwenden diff).

Die Verwendung commist schneller, aber diese Geschwindigkeit geht zu Lasten der Notwendigkeit, zuerst Ihre Dateien zu sortieren. Es ist nicht sehr nützlich als "Reverse Diff".

Ryder
quelle
danke Ryder, das könnte für viele nützlicher sein als Kommunikation. Sie sollten einen Link zur Quellantwort erstellen (in Q in der rechten Navigation sind über ein halbes Dutzend verknüpft; es ist ein bisschen Arbeit, sie zu finden). Es wäre auch schön zu wissen, wie gut grep mit un- oder anders sortierten Eingaben umgeht und die entsprechenden Zeilennummern von Übereinstimmungen drucken kann.
Matt Wilkie
1
@mattwilkie Ich hatte das Bedürfnis, zurück zu kommen und die Verwendung der -vFlagge zu klären, nachdem ich selbst damit ausgerutscht war. Angenommen, Sie haben zwei CSV-Dateien, Datei1 und Datei2, und sie haben sowohl überlappende als auch nicht überlappende Zeilen. Wenn Sie alle und nur die nicht überlappenden Zeilen möchten, gibt using fgrep -v file1 file2nur die nicht überlappenden Zeilen in Datei2 und keine der zusätzlichen nicht überlappenden Zeilen in Datei1 zurück . Dies mag für einige offensichtlich sein, aber es ist besser, das Offensichtliche als das Risiko einer Fehlinterpretation anzugeben. In diesem speziellen Fall ist das Sortieren und Verwenden der Dateien commimmer noch die bessere Wahl.
Ryder
1
Vielen Dank, dass Sie zurückgekommen sind und Ryder geklärt haben. Die zusätzliche Aufmerksamkeit wird zur Kenntnis genommen und geschätzt (alles, um alte Dinge einfach wegrutschen zu lassen!). Ich habe die akzeptierte Antwort geändert, da die Kommunikation eindeutig die Wahl der Community ist, obwohl ich diese persönlich immer noch verwende, wenn das Sortieren unerwünscht ist.
Matt Wilkie
2
Eine weitere Komplikation bei der Verwendung grep: Jede leere Zeile in der ersten Datei stimmt mit jeder Zeile in der zweiten Datei überein. Stellen Sie sicher, dass file1keine Leerzeilen vorhanden sind. Andernfalls sehen die Dateien identisch aus.
Christopher Schultz
grep -Fxfes ist für mich.
Loxaxs
35

Wurde hier schon einmal gefragt: Unix-Befehl, um in zwei Dateien gemeinsame Zeilen zu finden

Sie können es auch mit Perl versuchen (Gutschrift geht hier )

perl -ne 'print if ($seen{$_} .= @ARGV) =~ /10$/'  file1 file2
ChristopheD
quelle
1
Vielen Dank. Ich hätte gerne beide Antworten akzeptiert, da der Perl One Liner plattformübergreifend ist. Comm bekommt das Nicken, weil es einfacher ist.
Matt Wilkie
1
Perfekt. Verwendung des Cygwin-Terminals unter Windows und commnicht sofort verfügbar. Dies war die perfekte Alternative.
Qix - MONICA wurde am
3
Dabei ist es egal, wie die Zeilen bestellt werden. Es ist genauer als Comm.
enl8enmentnow
1
Eine Erklärung finden Sie hier: stackoverflow.com/questions/17552789/…
Chris Koknat
17

Ich habe gerade den Befehl comm aus diesem Thread gelernt, wollte aber noch etwas hinzufügen: Wenn die Dateien nicht sortiert sind und Sie die Originaldateien nicht berühren möchten, können Sie die Ausgabe des Befehls sort leiten. Dadurch bleiben die Originaldateien erhalten. Funktioniert in Bash, ich kann nichts über andere Muscheln sagen.

comm -1 -2 <(sort file1) <(sort file2)

Dies kann erweitert werden, um die Befehlsausgabe anstelle von Dateien zu vergleichen:

comm -1 -2 <(ls /dir1 | sort) <(ls /dir2 | sort)
Greg Mueller
quelle
9

Der einfachste Weg ist:

awk 'NR==FNR{a[$1]++;next} a[$1] ' file1 file2

Dateien müssen nicht sortiert werden.

Gopu
quelle
1
Dies unterscheidet sich von den meisten Antworten hier darin, dass Sie damit Quellvorlagen rekonstruieren können. Ich habe zwei Dateien aus demselben Wrapper erstellt, wobei an einigen Stellen unterschiedlicher Text eingefügt wurde. Diese Antwort ermöglichte es mir, den Wrapper wiederherzustellen.
Lucas Gonze
1

Nur zur Information, ich habe ein kleines Tool für Windows erstellt, das dasselbe tut wie "grep -F -x -f Datei1 Datei2" (da ich unter Windows nichts gefunden habe, was diesem Befehl entspricht)

Hier ist es: http://www.nerdzcore.com/?page=commonlines

Die Verwendung ist "CommonLines inputFile1 inputFile2 outputFile".

Quellcode ist ebenfalls verfügbar (GPL)

Zivilyn Bane
quelle
1

In Windows können Sie ein Powershell- Skript mit CompareObject verwenden

compare-object -IncludeEqual -ExcludeDifferent -PassThru (get-content A.txt) (get-content B.txt)> MATCHING.txt | Out-Null #Find Matching Lines

CompareObject:

  • IncludeEqual ohne -ExcludeDifferent: Alles
  • ExcludeDifferent ohne -InclueEqual: Nichts
Würger
quelle