2016-01-06 344 views
6

Ich habe eine Datei1, die ein paar Zeilen (Zehner) hat, und eine viel längere Datei2 (~ 500.000 Zeilen). Die Zeilen in jeder Datei sind nicht identisch, obwohl es eine Teilmenge von Feldern gibt, die identisch sind. Ich möchte Felder 3-5 von jeder Zeile in Datei1 nehmen und suche Datei2 nach dem gleichen Muster (nur diese drei Felder, in der gleichen Reihenfolge - in Datei2, sie fallen in Felder 2-4). Wenn eine Übereinstimmung gefunden wird, möchte ich die entsprechende Zeile aus Datei1 löschen.awk/sed/grep um Zeilen zu löschen, die Felder in einer anderen Datei enthalten

ZB file1:

2016-01-06T05:38:31 2016-01-06T05:23:33 2016006 120E A TM Current 
2016-01-06T07:34:01 2016-01-06T07:01:51 2016006 090E B TM Current 
2016-01-06T07:40:44 2016-01-06T07:40:41 2016006 080E A TM Alt 
2016-01-06T07:53:50 2016-01-06T07:52:14 2016006 090E A TM Current 
2016-01-06T08:14:45 2016-01-06T08:06:33 2016006 080E C TM Current 

file2:

2016-01-06T07:35:06.87 2016003 100E C NN Current 0 
2016-01-06T07:35:09.97 2016003 100E B TM Current 6303 
2016-01-06T07:36:23.12 2016004 030N C TM Current 0 
2016-01-06T07:37:57.36 2016006 090E A TM Current 399 
2016-01-06T07:40:29.61 2016006 010N C TM Current 0 

... (und auf 500.000 Zeilen)

Also in diesem Fall möchte ich die vierte Zeile löschen von file1 (an Ort und Stelle).

Im Folgenden findet die Zeilen, die ich löschen will:

grep "$(awk '{print $3,$4,$5}' file1)" file2 

So eine Lösung für Rohr dieser zu sed sein kann, aber ich bin mir nicht klar, wie ein Übereinstimmungsmuster setzen in einem verrohrt Eingang sed. Und die Online-Suche legt nahe, dass awk das alles kann (oder vielleicht sed oder etwas anderes), und sich fragt, wie eine saubere Lösung aussehen würde.

Auch Geschwindigkeit ist etwas wichtig, weil andere Prozesse versuchen, die Dateien zu ändern, während dies vor sich geht (ich weiß, dass dies mehr Komplikationen ergeben kann ...). Übereinstimmungen werden im Allgemeinen am Ende von Datei2 gefunden, nicht am Anfang (falls es eine Möglichkeit gibt, Datei2 von unten nach oben zu durchsuchen).

+0

pluse-uno für hervorragend beschriebenes Problem. Schreib weiter und viel Glück. – shellter

Antwort

4
$ awk 'NR==FNR{file2[$2,$3,$4]; next} !(($3,$4,$5) in file2)' file2 file1 
2016-01-06T05:38:31 2016-01-06T05:23:33 2016006 120E A TM Current 
2016-01-06T07:34:01 2016-01-06T07:01:51 2016006 090E B TM Current 
2016-01-06T07:40:44 2016-01-06T07:40:41 2016006 080E A TM Alt 
2016-01-06T08:14:45 2016-01-06T08:06:33 2016006 080E C TM Current 

Die Tatsache, dass file2 500.000 Zeilen enthält kein Problem für awk WRT Speicher oder Ausführungsgeschwindigkeit sein sollte - es sollte etwa 1 Sekunde oder weniger selbst im schlimmsten Fall abzuschließen in.

Mit jedem UNIX-Befehl, die ursprüngliche Datei zu überschreiben Sie gerade tun:

cmd file > tmp && mv tmp file 

so in diesem Fall:

awk '...' file2 file1 > tmp && mv tmp file1 
+0

Danke. Ich sehe, wie das funktioniert, und es ist ziemlich schnell. Ich habe versucht, es umgekehrt zu tun, lesen Sie file1 in ein Array (da es so viel kleiner ist), aber ich bin nicht klar, wie man dann Zeilen von file1, die nicht übereinstimmen, zu drucken. – trid3

+0

So, jetzt wissen Sie, dass das Lesen von Datei1 in ein Array der falsche Ansatz ist, oder? Dadurch würden Sie Speicher sparen, aber dann müssten Sie für jede Zeile der Datei 2 einmal das gesamte Array file1 durchlaufen, so dass sich die Zeit erhöhen würde, die das Skript benötigt, um mit einem Multiplikationsfaktor der Anzahl der Zeilen zu laufen Datei1. –

+0

ZB etwas wie dieses: awk 'NR == FNR {file1 [$ 3, $ 4, $ 5]; next}! (($ 2, $ 3, $ 4) in Datei1) {print XX} 'file1 file2. Was könnte XX sein? Wenn wir file1 einfach für ($ 2, $ 3, $ 4) grepsen könnten (jetzt, da wir wissen, dass es in file2 nicht existiert), und das ausdrucken, würde das den Trick machen. – trid3

1

Sie können nicht passenden Zeilen in file1 finden:

$ grep -v -F -f <(awk '{ print $3,$4,$5 }' file2) file1 
2016-01-06T05:38:31 2016-01-06T05:23:33 2016006 120E A TM Current 
2016-01-06T07:34:01 2016-01-06T07:01:51 2016006 090E B TM Current 
2016-01-06T07:40:44 2016-01-06T07:40:41 2016006 080E A TM Alt 
2016-01-06T08:14:45 2016-01-06T08:06:33 2016006 080E C TM Current 

einfach diese irgendwo umleiten und überschreiben file1 danach.

+0

Absolut nicht tun, da, obwohl es die erwartete Ausgabe bei dieser Beispieleingabe erzeugen kann, Sie im Allgemeinen falsche Übereinstimmungen erhalten werden, abhängig vom Inhalt der zwei Dateien, da es den Inhalt von Datei2 über die gesamte Zeile gräbt von Datei1 statt nur in den Zielfeldern von Datei1. –

Verwandte Themen