Wie vergleiche ich zwei verschiedene Dateien Zeile für Zeile in Unix?

13

Datei1:

123
234
345
456

Datei2:

123
234
343
758

Erwartete Ausgabe: File3:

TRUE
TRUE
FALSE
FALSE

Daher sollte der Code zwei Dateien vergleichen und 'TRUE' ausgeben, wenn er übereinstimmt, andernfalls sollte er in der neuen Datei 'FALSE' ausgeben. Könnte jemand bitte die Lösung dafür liefern?

Velu
quelle
10
Was passiert, wenn die beiden Dateien ungleich lang sind? Mit welchem ​​Teil der Lösung dieses Problems haben Sie Probleme?
Kusalananda
9
Vielleicht möchten Sie einen Blick darauf werfen diff.
Panki
2
Ein weiterer nützlicher Befehl in diesen Situationen ist comm. Es macht es einfach, Zeilen aufzulisten, die beide Dateien gemeinsam haben oder für die eine oder die andere eindeutig sind.
Giacomo Alzetta
1
@GiacomoAlzetta Das Problem commist, dass sortierte Eingaben erforderlich sind. Abgesehen von der Tatsache , dass das Beispiel in der Frage nicht sortierten Eingang hat, ist die Frage nie behauptet , dass dies die eigentlichen Daten , die verwendet wird, und sagt nichts über die Reihenfolge der Daten.
Kusalananda
2
Der nlTrick von αғsнιη ist nützlich, commum die Dateien zu sortieren.
Glenn Jackman

Antworten:

57

Verwenden Sie den diffBefehl wie folgt in einer bashoder einer anderen Shell, die <(...) Prozessersetzungen unterstützt , oder Sie können ihn wie hier gezeigt emulieren :

diff --new-line-format='FALSE'$'\n' \
     --old-line-format='' \
     --unchanged-line-format='TRUE'$'\n' \
<(nl file1) <(nl file2)

Die Ausgabe wäre:

TRUE
TRUE
FALSE
FALSE

--new-line-format='FALSE'$'\n, Drucken, FALSEwenn Zeilen unterschiedlich waren und --old-line-format=''Deaktivieren der Ausgabe, wenn Zeilen unterschiedlich waren, für Datei1, der als alter Befehl zum Vergleichen von Dateien bezeichnet wird FALSE.

--unchanged-line-format='TRUE'$'\n', drucke TRUEwenn die Zeilen gleich waren. Die $'\n'Escape-Syntax im C-Stil wird verwendet, um nach jeder Zeilenausgabe eine neue Zeile zu drucken.

αғsнιη
quelle
25

Angenommen, die Dateien enthalten keine Tabulatorzeichen:

$ paste file1 file2 | awk -F '\t' '{ print ($1 == $2 ? "TRUE" : "FALSE") }'
TRUE
TRUE
FALSE
FALSE

Hiermit werden pastezwei durch Tabulatoren getrennte Spalten mit dem Inhalt der beiden Dateien in einer der Spalten erstellt. Der awkBefehl vergleicht die beiden Spalten in jeder Zeile und gibt aus, TRUEob die Spalten identisch sind, andernfalls wird gedruckt FALSE.

Kusalananda
quelle
10

Angenommen, beide Dateien haben die gleiche Anzahl von Zeilen:

awk '{getline f2 < "file2"; print f2 == $0 ? "TRUE" : "FALSE"}' file1

Dies führt einen numerischen Vergleich durch, wenn die zu vergleichenden Zeichenfolgen Zahlen sind und ansonsten lexikalisch. Zum Beispiel 100und 1.0e2würde als identisch angesehen. Wechseln Sie f2"" == $0in jeden Fall zu , um einen lexikalischen Vergleich zu erzwingen.

Je nach awkImplementierung erfolgt der lexikalische Vergleich wie unter Verwendung von memcmp()(Byte-zu-Byte-Vergleich) oder wie unter Verwendung von strcoll()(ob die beiden Zeichenfolgen in der Sortierreihenfolge des Gebietsschemas gleich sortiert sind). Dies kann in einigen Regionen, in denen die Reihenfolge für einige Zeichen nicht richtig definiert ist, zu Unterschieden führen, und zwar nicht bei allen Eingaben mit Dezimalstellen wie in Ihrem Beispiel.

Stéphane Chazelas
quelle
8

Python 3

with open('file1') as file1, open('file2') as file2:
    for line1, line2 in zip(file1, file2):
        print(line1 == line2)

Ausgabe:

True
True
False
False

Wenn Sie benötigen TRUEund FALSEin Großbuchstaben, tauschen Sie die Druckleitung mit einem der folgenden:

print(str(line1 == line2).upper())
print('TRUE' if line1 == line2 else 'FALSE')
wjandrea
quelle
2
Führen Sie in Python 2 import itertoolszuerst einen Befehl aus und verwenden Sie dann itertools.izipanstelle von zip. Andernfalls werden beide Dateien in den Speicher gelesen, möglicherweise wird zu viel Speicher verwendet.
Pkt.
4

In bash, aus jeder Datei in einer whileLeseschleife, Vergleichen der Leseleitungen und den Druck TRUEoder FALSEentsprechend:

while IFS= read -r -u3 line1; IFS= read -r -u4 line2; do
    [[ $line1 == $line2 ]] && echo TRUE || echo FALSE
done 3<file1 4<file2

Die beiden Aufrufe zum readLesen von Datei-Deskriptor 3 bzw. 4. Die Dateien werden mit zwei Eingabeumleitungen in die Schleife zu diesen umgeleitet.

Glenn Jackman
quelle
0
Tried with awk command and it worked fine


awk 'NR==FNR{a[$1];next}{if ($1 in a){print "TRUE"} else{print "False"}}' file1 file2

Ausgabe

TRUE
TRUE
False
False
Praveen Kumar BS
quelle