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 %3
und 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 %123
Token und jede Zeile enthält ein solches Token.
Die \( \)
Metazeichen markieren eine Match-Gruppe, auf die bei der Ersetzung dann über die \1
Rü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 grep
entfernt der Teil alle %123
Zeilen, die keine Token sind.
Antwort2
grep -o
In diesem Fall ist es möglicherweise besser, Folgendes zu verwenden :
grep -oP '\B%[0-9]{1,3}\b' inputfile
Vorausgesetzt, Ihre Version von grep
unterstützt Perl-kompatible reguläre Ausdrücke ( -P
). Andernfalls:
grep -o '\B%[0-9]\{1,3\}\b' inputfile
Mit GNU sed
kö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 sed
ist 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 %digit
Kombination - 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.