Wie verwende ich sed -e 's///' für alles außer einem bestimmten Muster?

Wie verwende ich sed -e 's///' für alles außer einem bestimmten Muster?

Wie kann ich in einem String alles außer % und jede direkt folgende Zahl durch sed ersetzen? Also alles außer Strings wie:

%1 %1000 %55 usw.

Gegeben sind Zeichenfolgen dieser Form:

    1: [18x14] [history 1/2000, 268 bytes] %3
    2: [18x14] [history 1/2000, 268 bytes] %4 (active)

Ich möchte nur die Teile %3und haben %4. Die Zahlen können bis gehen 999.

Antwort1

$ sed 's/^.*\(%[0-9]\+\).*$/\1/' input

Angenommen, eine Zeile enthält höchstens eines dieser %123Token und jede Zeile enthält ein solches Token.

Die \( \)Metazeichen markieren eine Match-Gruppe, auf die bei der Ersetzung dann über die \1Rückreferenz verwiesen wird. ^/ $entspricht dem Zeilenanfang/-ende.

Andernfalls können Sie die Eingabe vorfiltern, zB:

$ grep '%[0-9]\+' input | sed 's/^.*\(%[0-9]\+\).*$/\1/'

(wenn nicht alle Zeilen ein solches Token enthalten)

Eine andere Variante:

$ sed 's/\(%[0-9]\+\)/\n\1\n/g' | grep '%[0-9]'

(wenn eine Zeile mehrere dieser Token enthalten kann)

Dabei werden Zeilenumbrüche direkt vor und nach jedem Token eingefügt - im ersten Teil der Pipe. Anschließend grepentfernt der Teil alle %123Zeilen, die keine Token sind.

Antwort2

grep -oIn diesem Fall ist es möglicherweise besser, Folgendes zu verwenden :

grep -oP '\B%[0-9]{1,3}\b' inputfile

Vorausgesetzt, Ihre Version von grepunterstützt Perl-kompatible reguläre Ausdrücke ( -P). Andernfalls:

grep -o '\B%[0-9]\{1,3\}\b' inputfile

Mit GNU sedkönnte man Leerzeichen in Zeilenumbrüche umwandeln und die gewünschten Zeilen erhalten:

sed 'y/ /\n/' inputfile | sed '/^%[0-9]\{1,\}/!d'

Antwort3

Beim Arbeiten mit sedist es fast immer ratsam:

/address then/s/earch/replace/

Dafür gibt es zwei Gründe. Der erste ist, dass mit mehreren Zeilen /addressing/schneller ist - es ist nur optimiert, umfindeneine Übereinstimmung und macht sich nicht die Mühe, nur Teile einer Zeile zum Bearbeiten auszuwählen, und kann so die Ergebnisse schneller eingrenzen.

Der zweite Grund besteht darin, dass Sie mehrere Bearbeitungsvorgänge von derselben Adresse aus durchführen können – das macht die Dinge viel einfacher.

In diesem Fall macht es natürlich keinen praktischen Unterschied, wenn man nur die Daten berücksichtigt, die Sie zeigen. Trotzdem würde ich das, wonach Sie fragen, so machen:

sed '/^[^%]*\|[^0-9]*$/s///g' <<\DATA
    1: [18x14] [history 1/2000, 268 bytes] %3
    2: [18x14] [history 1/2000, 268 bytes] %4 (active)
DATA

#OUTPUT
%3
%4

Es werden nur alle Zeichen ausgewählt, dienicht-%Zeichen vom Zeilenanfang und allenicht numerischZeichen vom Ende der Zeile in der Adresse und entfernt sie dann mit s///- und das war's.

In seiner aktuellen Form könnte es Daten auf unerwartete Weise verfälschen, wenn Sie ihm Zeilen zuführennichtenthält eine %digitKombination - und deshalb ist die Adressierung wichtig. Wenn wir es ein wenig ändern:

/%[0-9]/s/[^%]*\|[^0-9]*$//g

Es wird sichererUndSchneller.

Antwort4

Meine Lösung verwendet kein sed, sondern grep mit erweiterten regulären Ausdrücken und nur übereinstimmenden Optionen.


$ cat file
1: [18x14] [history 1/2000, 268 bytes] %3
2: [18x14] [history 1/2000, 268 bytes] %4 (active)
$ cat file | grep -Eo '%[0-9]+'
%3
%4

In diesem Fall ist die Verwendung von grep einfacher als die Verwendung von sed.

verwandte Informationen