ubuntuusers.de

sed/awk multiline pattern search and delete - geht es besser?

Status: Gelöst | Ubuntu-Version: Ubuntu 11.10 (Oneiric Ocelot)
Antworten |

riffraff

Avatar von riffraff

Anmeldungsdatum:
1. Oktober 2006

Beiträge: 486

Wohnort: Im kühlen Norden

Hallo,

ich zerbreche mir gerade den Kopf über ein kleines Problem -und ich bin nicht wirklich zufrieden mit meiner "Lösung" Evtl. kann mich ja jemand auf die richtige Spur bringen.

Ich habe eine Datei in der die Zeilen wie folgt aufgebaut sind:

ABC1239;Testuser Eins, 2345, OLP, TRIGGER, FG, 1234,
ABC1239;Testuser Eins, 2345, OLP, HURRA, FG, 1234,
TZU4679;Cluever Bernd, 3333, IKO, HILP, SD, 3312,
IOI4679;Werner Wernere, 7655, OPL, UIOLP, EW, 2222,
IOI4679;Werner Wernere, 7677, LOP, TRIGGER, 12,9876,

Mein Ziel definiert sich folgendermassen:

Finde das Wort "TRIGGER" Merke Dir den ersten Ausdruck dieser Zeile bis zum Semikolon (Also so etwa: /^.*\;/ ) Schau in die nächste Zeile und WENN der erste Audruck übeinstimmt dann lösche die zweite Zeile.

Meine Lösung soweit (ohne die überprüfung ob der erste Parameter der gleiche ist):

1
2
3
4
sort komplett1 | sed '/TRIGGER/{
N
s/\n.*$//
}'

Ergebnis soll sein:

ABC1239;Testuser Eins, 2345, OLP, TRIGGER, FG, 1234,
TZU4679;Cluever Bernd, 3333, IKO, HILP, SD, 3312,
IOI4679;Werner Wernere, 7677, LOP, TRIGGER, 12,9876,

Ich hoffe, das ist verständlich Die Zeilen sind immer gleich aufgbaut - WORT;Wort Wort, Nummer, Wort, Wort, Wort, Nummer,

Anders ausgedrückt: Bei Zeilen die mit dem gleichen Wort beginnen wirf die Zeile weg, die NICHT das Wort "TRIGGER" enthält (so hört sich das eigentlich richtig gut an ☺ )

Ich habe auch mit awk und

awk -F"," '$4 ~ /TRIGGER/ {....

aber da komme ich gar nicht weiter.

Multiline Pattern geht mir im Moment völlig ab.

Mit meiner rudimentären Lösung (solange das sortieren noch korrekt klappt) kann ich zwar leben, da ich die Datei vorher sortiere und sicher sein kann, dass die zeilen dann auch doppelt enthalten sind; aber mein Wunsch wäre eine Lösung bei der der Abgleich auf den ersten Parameter der Zeile stattfindet UND (wenn möglich) das ganze auch funktioniert wenn "TRIGGER" in der Zeile dahinter steht!

Jede Hilfe ist willkommen ☺

Ich kann aber nur awk und sed einsetzen - kein python, perl oder ähnliches.

r-h-t

Anmeldungsdatum:
5. Januar 2012

Beiträge: 75

Wenn man ein Array benutzt, sollte das so gehen:

1
2
3
4
5
BEGIN { FS = ";" }

(($1 in a) && ($2 ~ /TRIGGER/)) || (!($1 in a)) { a[$1] = $0 }

END { for (i in a) print a[i] }

riffraff

(Themenstarter)
Avatar von riffraff

Anmeldungsdatum:
1. Oktober 2006

Beiträge: 486

Wohnort: Im kühlen Norden

r-h-t - You made my day ☺

Das funktioniert hervorragend. Und wieder ist die Lösung so peinlich simpel und wieder bin ich nicht drauf gekommen.

Zum Glück gibt es dieses Forum und seine tollen User! ☺

Danke!

track

Avatar von track

Anmeldungsdatum:
26. Juni 2008

Beiträge: 7174

Wohnort: Wolfen (S-A)

Das kann man mit awk ziemlich elegant auch ohne Arrays umsetzen. Dazu würde ich

  1. den Worttrenner auf ; einstellen

  2. wenn "TRIGGER" in der Zeile vorkommt, das 1. Wort zwischenspeichern
    (wenn nicht, den Speicher wieder löschen)

  3. wenn das aktuelle 1. Wort mit dem Speicher übereinstimmt, die Zeile unterdrücken:

#! /usr/bin/awk -f

BEGIN	{	FS= ";"  }

	{	if (merke != $1)  print $0; 
		if ($2 ~ " TRIGGER,")	merke= $1; 
		else			merke= ""; 	}

Das selbe als Einzeiler:

awk -F ";" '{if (merke != $1) print $0; if ($2 ~ " TRIGGER,") merke= $1; else merke= ""}'  Quelldatei  >  neue_Datei 

Man muss nur aufpassen, wenn der TRIGGER eventuell als Teil-Ausdruck in anderen Datenfeldern vorkommt.
Dann muss man die Triggerbedingung genauer formulieren.

Die Lösung von r-h-t reagiert auch, wenn der TRIGGER schon mehrere Zeilen vorher stand, z.B. bei:

TZU4679;Cluever Bernd, 3333, IKO, TRIGGER, SD, 3312,
ABC1239;Testuser Eins, 2345, OLP, TRIGGER, FG, 1234,
ABC1239;Testuser Eins, 2345, OLP, HURRA, FG, 1234,
TZU4679;Cluever Bernd, 3333, IKO, HILP, SD, 3312,
IOI4679;Werner Wernere, 7655, OPL, UIOLP, EW, 2222,
IOI4679;Werner Wernere, 7677, LOP, TRIGGER, 12,9876,

Du musst mal gucken, ob das etwas ausmacht.

LG,

track

rklm Team-Icon

Projektleitung

Anmeldungsdatum:
16. Oktober 2011

Beiträge: 13215

track schrieb:

Das kann man mit awk ziemlich elegant auch ohne Arrays umsetzen.

So hätte ich das auch gemacht. Das hat außerdem den Vorteil, dass es mit großen Dateien deutlich besser funktioniert, weil awk nicht den gesamten Inhalt im Speicher halten muss. Ich finde es auch verständlicher als die Lösung von r-h-t, die u.U. auch die Reihenfolge der Ausgabe ändert (wg. assoziativem Array). ☺

Ciao

robert

r-h-t

Anmeldungsdatum:
5. Januar 2012

Beiträge: 75

track schrieb:

Die Lösung von r-h-t reagiert auch, wenn der TRIGGER schon mehrere Zeilen vorher stand [...].

Es wurde auch nicht explizit formuliert, dass dies nicht so sein kann.

rklm schrieb:

So hätte ich das auch gemacht. Das hat außerdem den Vorteil, dass es mit großen Dateien deutlich besser funktioniert, weil awk nicht den gesamten Inhalt im Speicher halten muss.

Ob das Probleme verursacht, kann ich nicht wissen, da ich nicht weiß, wie groß die Eingabedateien sind.

Ich finde es auch verständlicher als die Lösung von r-h-t, die u.U. auch die Reihenfolge der Ausgabe ändert (wg. assoziativem Array). ☺

Letzteres erschien mir nicht wichtig, da riffraff die Datei ja ursprünglich sogar sortierte. Über Verständlichkeit oder Unverständlichkeit kann man sich streiten, jedoch ist das Prinzip fast dasselbe.

Anmerken möchte ich jedoch noch dies: die andere Lösung von track funktioniert meines Erachtens nicht korrekt. Nämlich dann, wenn von zwei Zeilen mit demselben "Schlüssel" die Zeile, in der TRIGGER enthalten ist, als zweite kommt.

ABC1239;Testuser Eins, 2345, OLP, TRIGGER, FG, 1234,
ABC1239;Testuser Eins, 2345, OLP, HURRA, FG, 1234,
TZU4679;Cluever Bernd, 3333, IKO, HILP, SD, 3312,
IOI4679;Werner Wernere, 7655, OPL, UIOLP, EW, 2222,
IOI4679;Werner Wernere, 7677, LOP, TRIGGER, 12,9876,

Bei der ersten Zeile ist die Variable merke garantiert von $1 verschieden. Also wird die Zeile ausgedruckt, obwohl sie nicht TRIGGER enthält.

rklm Team-Icon

Projektleitung

Anmeldungsdatum:
16. Oktober 2011

Beiträge: 13215

r-h-t schrieb:

track schrieb:

Die Lösung von r-h-t reagiert auch, wenn der TRIGGER schon mehrere Zeilen vorher stand [...].

Es wurde auch nicht explizit formuliert, dass dies nicht so sein kann.

rklm schrieb:

So hätte ich das auch gemacht. Das hat außerdem den Vorteil, dass es mit großen Dateien deutlich besser funktioniert, weil awk nicht den gesamten Inhalt im Speicher halten muss.

Ob das Probleme verursacht, kann ich nicht wissen, da ich nicht weiß, wie groß die Eingabedateien sind.

Stimmt. M.E. ist es aber robuster, wenn man die Lösung so auslegt, dass sie auch mit großen Datenmengen gut klarkommt. Aber dazu siehe unten.

Letzteres erschien mir nicht wichtig, da riffraff die Datei ja ursprünglich sogar sortierte. Über Verständlichkeit oder Unverständlichkeit kann man sich streiten, jedoch ist das Prinzip fast dasselbe.

Das sehe ich anders: nicht nur vom Laufzeitverhalten ist es ein wesentlicher Unterschied, ob die Bearbeitung mit wenig Kontext auskommt oder aber den gesamten Input speichern muss, bevor die Ausgabe generiert werden kann. Außerdem liebe ich es, Lösungen möglichst effizient auszulegen; jaja, ich weiß: vorzeitige Optimierung ist die Wurzel allen Übels - aber da das hier Hobby ist und knifflige Aufgaben mehr Spaß machen als einfache... ☺

Anmerken möchte ich jedoch noch dies: die andere Lösung von track funktioniert meines Erachtens nicht korrekt. Nämlich dann, wenn von zwei Zeilen mit demselben "Schlüssel" die Zeile, in der TRIGGER enthalten ist, als zweite kommt.

Das kann man natürlich durch Sortieren retten, falls es nicht mehrere Dateien mit demselben Schlüsselfeld an der ersten Stelle gibt.

Man sieht sehr schön, wie viel Genauigkeit noch in der Problembeschreibung fehlt:

  • Größe der Eingabe

  • Eingabe sortiert oder nicht, bzw.

  • Häufigkeit von Schlüsseln in der ersten Spalte

  • Geht es um eine einmalige Lösung oder etwas, das dauerhaft laufen muss

Ciao

robert

track

Avatar von track

Anmeldungsdatum:
26. Juni 2008

Beiträge: 7174

Wohnort: Wolfen (S-A)

r-h-t schrieb:

Anmerken möchte ich jedoch noch dies: die andere Lösung von track funktioniert meines Erachtens nicht korrekt. Nämlich dann, wenn von zwei Zeilen mit demselben "Schlüssel" die Zeile, in der TRIGGER enthalten ist, als zweite kommt.

Stimmt !
Das ist wieder so eine heimliche Zusatzbedingung, die in der Problembeschreibung gar nicht enthalten war:

Mein Ziel definiert sich folgendermassen:

Finde das Wort "TRIGGER" Merke Dir den ersten Ausdruck dieser Zeile bis zum Semikolon (Also so etwa: /^.*\;/ ) Schau in die nächste Zeile und WENN der erste Audruck übeinstimmt dann lösche die zweite Zeile.

Von vertauschter Reihenfolge war keine Rede, im Gegenteil ! Erst aus dem Ausgabebeispiel hätte man das erraten können. 😉

Tja, die Sache mit dem missverständlichen Pflichtenheft ...

track

riffraff

(Themenstarter)
Avatar von riffraff

Anmeldungsdatum:
1. Oktober 2006

Beiträge: 486

Wohnort: Im kühlen Norden

Ihr seid so klasse ☺ Ich lerne hier immer wieder geniale Sachen dazu.

Die Lösung von r-h-t ist wirklich klasse für mich - und das es sogar greift wenn die Zeilen weiter auseinanderstehen macht es dazu noch perfekter. Ich sortiere die Files auf jeden Fall am Ende, von daher kann die erste Ausgabe ruhig durcheinandergewürfelt werden.

Auf jeden Fall kommen alle Hinweise in die snippets meiner awk-Dokumentation ☺

Viele Grüße und allen ein schönes Wochenende - jetzt gehts auf Sofa für mich; bin schwer erkältet ☹

r-h-t

Anmeldungsdatum:
5. Januar 2012

Beiträge: 75

track schrieb:

Das ist wieder so eine heimliche Zusatzbedingung, die in der Problembeschreibung gar nicht enthalten war:

Leider doch. Weiter unten steht im ersten Beitrag des Threads:

Anders ausgedrückt: Bei Zeilen die mit dem gleichen Wort beginnen wirf die Zeile weg, die NICHT das Wort "TRIGGER" enthält (so hört sich das eigentlich richtig gut an ☺ )

"Anders ausgedrückt": ein Schlüsselbegriff in jedem geisteswissenschaftlichen Studium. Deswegen bin ich wahrscheinlich darauf angesprungen. 😉

Antworten |