GNU/Linux >> LINUX-Kenntnisse >  >> Linux

Zwei Spalten verschiedener Dateien vergleichen und bei Übereinstimmung drucken?

Ich verwende Solaris 10 und daher funktionieren grep-Optionen mit -f nicht.

Ich habe zwei durch Pipes getrennte Dateien:

Datei1:

abc|123|BNY|apple|
cab|234|cyx|orange|
def|kumar|pki|bird|

Datei 2:

abc|123|
kumar|pki|
cab|234

Ich möchte die ersten beiden Spalten von Datei2 mit Datei1 vergleichen (den gesamten Inhalt von Datei1 in den ersten beiden Spalten durchsuchen), wenn sie übereinstimmen, die übereinstimmende Zeile von Datei1 drucken. Suchen Sie dann nach der zweiten Zeile von Datei 2 und so weiter.

Erwartete Ausgabe:

abc|123|BNY|apple|
cab|234|cyx|orange|

Die Dateien, die ich habe, sind riesig und enthalten etwa 400.000 Zeilen, daher möchte ich die Ausführung schnell machen.

Akzeptierte Antwort:

Dafür wurde awk entwickelt:

$ awk -F'|' 'NR==FNR{c[$1$2]++;next};c[$1$2] > 0' file2 file1
abc|123|BNY|apple|
cab|234|cyx|orange|

Erklärung

  • -F'|' :setzt das Feldtrennzeichen auf | .
  • NR==FNR :NR ist die aktuelle Eingabezeilennummer und FNR die Zeilennummer der aktuellen Datei. Die beiden sind nur gleich, während die erste Datei gelesen wird.
  • c[$1$2]++; next :Wenn dies die erste Datei ist, speichern Sie die ersten beiden Felder im c Reihe. Springen Sie dann zur nächsten Zeile, damit dies nur auf die 1. Datei angewendet wird.

  • c[$1$2]>0 :Der Else-Block wird nur ausgeführt, wenn dies die zweite Datei ist, also prüfen wir, ob die Felder 1 und 2 dieser Datei bereits gesehen wurden (c[$1$2]>0 ) und wenn ja, drucken wir die Zeile. In awk , ist die Standardaktion, die Zeile so zu drucken, wenn c[$1$2]>0 wahr ist, wird die Zeile gedruckt.

Alternativ, da Sie mit Perl getaggt haben:

perl -e 'open(A, "file2"); while(<A>){/.+?|[^|]+/ && $k{$&}++};
         while(<>){/.+?|[^|]+/ && do{print if defined($k{$&})}}' file1

Erklärung

Die erste Zeile öffnet file2 , lesen Sie alles bis zum 2. | (.+?|[^|]+ ) und speichern Sie das (die $& ist das Ergebnis des letzten Übereinstimmungsoperators) in %k Hash.

Die zweite Zeile verarbeitet Datei1, verwendet dieselbe Regex, um die ersten beiden Spalten zu extrahieren und die Zeile auszugeben, wenn diese Spalten in %k definiert sind Hash.

Beide oben genannten Ansätze müssen die beiden ersten Spalten von file2 im Speicher halten. Das sollte kein Problem sein, wenn Sie nur ein paar hunderttausend Zeilen haben, aber wenn es so ist, könnten Sie so etwas wie

machen
cut -d'|' -f 1,2 file2 | while read pat; do grep "^$pat" file1; done

Aber das wird langsamer sein.

Verwandte Themen:Kopieren Sie alle installierten Programme und Dateien auf eine Festplatte (mit 32-Bit-Windows 7) und klonen/übertragen Sie sie auf einen anderen Computer mit 64-Bit-Windows 7?
Linux
  1. Linien zwischen (und ausschließenden) zwei Mustern drucken?

  2. Suchen Sie nach Textdateien, in denen zwei verschiedene Wörter vorhanden sind (beliebige Reihenfolge, beliebige Zeile)?

  3. Wie vergleiche ich zwei Dateien und füge dann eine Zeile an, die keine teilweise Übereinstimmung ist?

  4. Gemeinsame Linien zwischen zwei Dateien?

  5. wie man zwei Dateien konsistent Zeile für Zeile zusammenführt

So entfernen Sie Dateien und Verzeichnisse mit der Linux-Befehlszeile

Wie man Textdateien unter Linux vergleicht und zusammenführt

Wie man Textdateien unter Linux vergleicht und zusammenführt (Teil 2)

So vergleichen Sie zwei Dateien im Linux-Terminal

Vergleichen Sie zwei Dateien unter Linux – Verwenden Sie diff, vimdiff und colordiff

Unterschied in Leerzeichen zwischen zwei Dateien unter Linux