it-swarm.com.de

Kombiniere zwei Dateien mit awk

File1.txt

item1   carA
item2   carB
item3   carC
item4   platD
item5   carE

File2.txt

carA  platA
carB  platB
carC  platC
carE  platE

Gewünschte Ausgabe:

item1   platA
item2   platB
item3   platC
item4   platD
item5   platE

Wie kann ich es tun?

9
pawana

Die folgende Antwort basiert auf einem ähnliche Fragen und Antworten in SO mit einigen relevanten Änderungen:

$ awk 'FNR==NR {dict[$1]=$2; next} {$2=($2 in dict) ? dict[$2] : $2}1' file2.txt file1.txt 
item1 platA
item2 platB
item3 platC
item4 platD
item5 platE

Die Idee ist, eine Hash-Map mit Index zu erstellen und als Wörterbuch zu verwenden.

Für die zweite Frage, die Sie in Ihrem Kommentar gestellt haben (, was geändert werden soll, wenn die zweite Spalte von file1.txt die sechste Spalte ist ):

Wenn die Eingabedatei file1b.txt lautet:

item1 A5 B C D carA
item2 A4 1 2 3 carB
item3 A3 2 3 4 carC
item4 A2 4 5 6 platD
item5 A1 7 8 9 carE

Der folgende Befehl erledigt das:

$ awk 'FNR==NR {dict[$1]=$2; next} {$2=($6 in dict) ? dict[$6] : $6;$3="";$4="";$5="";$6=""}1' file2.txt file1b.txt 
item1 platA    
item2 platB    
item3 platC    
item4 platD    
item5 platE    
11
Yaron

Ich weiß, dass Sie awk gesagt haben, aber es gibt einen join -Befehl für diesen Zweck ...

{
  join -o 1.1,2.2 -1 2 -2 1 <(sort -k 2 File1.txt) <(sort -k 1 File2.txt)     
  join -v 1 -o 1.1,1.2 -1 2 -2 1 <(sort -k 2 File1.txt) <(sort -k 1 File2.txt) 
} | sort -k 1

Mit dem ersten join -Befehl wäre es ausreichend, wenn diese Zeile nicht vorhanden wäre:

item4   platD

Der Befehl lautet im Wesentlichen: Join basierend auf der zweiten Spalte der ersten Datei (-1 2) und der ersten Spalte der zweiten Datei (-2 1) und Ausgabe der ersten Spalte der ersten Datei und der zweite Spalte der zweiten Datei (-o 1.1,2.2). Das zeigt nur die Linien, die gepaart sind. Der zweite Verknüpfungsbefehl sagt fast das Gleiche, zeigt jedoch die Zeilen der ersten Datei an, die nicht gekoppelt werden konnten (-v 1), und gibt die erste Spalte der ersten Datei und die zweite Spalte der aus erste Datei (-o 1.1,1.2). Dann sortieren wir die Ausgabe von beiden kombiniert. sort -k 1 bedeutet Sortieren basierend auf der ersten Spalte, und sort -k 2 bedeutet Sortieren basierend auf der zweiten Spalte. Es ist wichtig, die Dateien basierend auf der Join-Spalte zu sortieren, bevor Sie sie an join übergeben.

Jetzt habe ich die Sortierung zweimal geschrieben, weil ich meine Verzeichnisse nicht gerne mit Dateien übersetze, wenn ich das ändern kann. Wie David Foerster bereits sagte, sollten Sie die Dateien je nach Größe der Dateien sortieren und zuerst speichern, damit Sie nicht darauf warten müssen, sie zweimal zu sortieren. Um eine Vorstellung von den Größen zu bekommen, ist hier die Zeit, die benötigt wird, um 1 Million und 10 Millionen Zeilen auf meinem Computer zu sortieren:

$ Ruby -e '(1..1000000).each {|i| puts "item#{i}   plat#{i}"}' | shuf > 1million.txt 
$ Ruby -e '(1..10000000).each {|i| puts "item#{i}   plat#{i}"}' | shuf > 10million.txt 
$ head 10million.txt 
item530284   plat530284
item7946579   plat7946579
item1521735   plat1521735
item9762844   plat9762844
item2289811   plat2289811
item6878181   plat6878181
item7957075   plat7957075
item2527811   plat2527811
item5940907   plat5940907
item3289494   plat3289494
$ TIMEFORMAT=%E
$ time sort 1million.txt >/dev/null
1.547
$ time sort 10million.txt >/dev/null
19.187

Das sind 1,5 Sekunden für 1 Million Zeilen und 19 Sekunden für 10 Millionen Zeilen.

6
JoL