sed: löscht alle Vorkommen eines Strings mit Ausnahme des ersten

14

Ich habe eine Protokolldatei mit Zeitstempeln. Gelegentlich befinden sich mehrere Zeitstempel in einer Zeile. Jetzt möchte ich alle Zeitstempel aus einer Zeile entfernen, aber den ersten behalten.

Ich kann s/pattern//2aber das erst beim zweiten Auftreten beseitigen und sedso etwas nicht zulassen s/pattern//2-.

Irgendwelche Vorschläge?

Folkert van Heusden
quelle
Ich hätte sagen sollen, dass es das Sed von busybox ist. Das tut mir leid.
Folkert van Heusden

Antworten:

4

Mit GNU sed:

sed 's/pattern//2g'

Das 2gibt an, dass das zweite Muster und alle anderen entfernt werden gsollen. Das wird also der erste bleiben.

αғsнιη
quelle
1
Welche Cygwin hat (anscheinend eine Portierung von) und welche MacOS nicht. Achh! Diese Lösung ist viel eleganter.
r_alex_hall
7

Dies sollte funktionieren (ersetzen Sie _ durch etwas anderes, falls es mit Ihren Protokollen kollidiert):

sed -e 's/pattern/_&/1' -e 's/\([^_]\)pattern//g' -e 's/_\(pattern\)/\1/'
jlliagre
quelle
1
Wenn Sie jemals ein eindeutiges Trennzeichen wünschen, verwenden Sie \n.
mikeserv
5
sed -e ':begin;s/pattern//2;t begin'

oder ohne sed gehe zu:

sed -e 's/\(pattern\)/\1\n/;h;s/.*\n//;s/pattern//g;H;g;s/\n.*\n//'

Die generischen Lösungen zum Entfernen aus der n-ten Position (zum Beispiel 3) sind:

sed -e ':begin;s/pattern//4;t begin'
sed -e 's/\(pattern\)/\1\n/;h;s/.*\n//3;s/pattern//g;H;g;s/\n.*\n//'
jfg956
quelle
1

Eine geringfügige Änderung der Antwort von @ jillagre (aus Gründen der Robustheit modifiziert) könnte wie folgt aussehen:

sed 's/p\(attern\)/p\n\1/;s///g;s/\n//'

... aber in einigen Fällen sedmüssen Sie möglicherweise ndie rechte Seite der ersten s///Ubstitution-Anweisung durch ein wörtliches \newline-Zeichen ersetzen.

mikeserv
quelle