sed: Nur passende Gruppe drucken


133

Ich möchte die letzten beiden Zahlen (eine int, eine float; gefolgt von einem optionalen Leerzeichen) abrufen und nur diese drucken.

Beispiel:

foo bar <foo> bla 1 2 3.4

Sollte drucken:

2 3.4

Bisher habe ich folgendes:

sed -n  's/\([0-9][0-9]*[\ \t][0-9.]*[\ \t]*$\)/replacement/p' 

wird mir geben

foo bar <foo> bla 1 replacement

Wenn ich jedoch versuche, es durch Gruppe 1 zu ersetzen, wird die gesamte Zeile gedruckt.

sed -n  's/\([0-9][0-9]*[\ \t][0-9.]*[\ \t]*$\)/\1/p' 

Wie kann ich nur den Abschnitt der Zeile drucken, der dem regulären Ausdruck in der Gruppe entspricht?

Antworten:


138

Passen Sie die gesamte Zeile an, fügen Sie also .*am Anfang Ihrer Regex ein hinzu. Dadurch wird die gesamte Zeile durch den Inhalt der Gruppe ersetzt

echo "foo bar <foo> bla 1 2 3.4" |
 sed -n  's/.*\([0-9][0-9]*[\ \t][0-9.]*[ \t]*$\)/\1/p'
2 3.4

38
Ich musste die -rOption "--regexp-extended" hinzufügen, da sonst invalid reference \1 on der RHS-Fehler des Befehls s angezeigt wurde .
Daniel Sokolowski

15
@ DanielSokolowski Ich denke, Sie bekommen diesen Fehler, wenn Sie (und )anstelle von \(und verwenden \).
Daniel Darabos

3
.*Denken Sie auch daran, am Ende des regulären Ausdrucks hinzuzufügen , wenn sich die zu extrahierende Zeichenfolge nicht immer am Ende der Zeile befindet.
Teemu Leisti

3
Das wird bei mir nicht funktionieren, weil .*es gierig ist und sed keine nicht gierige hat.*?
sondra.kinsey

@ DanielDarabos Erwähne das nur (und )werde in Ubuntu 16.04 keinen Fehler auslösen. Ich denke, dieser Kommentar ist veraltet.
Li Haonan

72

grep ist das richtige Werkzeug zum Extrahieren.

Verwenden Sie Ihr Beispiel und Ihren regulären Ausdruck:

kent$  echo 'foo bar <foo> bla 1 2 3.4'|grep -o '[0-9][0-9]*[\ \t][0-9.]*[\ \t]*$'
2 3.4

12
ideal

grep -o portiert nicht auf Systeme, auf denen msysgit ausgeführt wird, sed jedoch.
Cchamberlain

In der von @jozxyqk verknüpften Frage finden Sie eine Antwort, bei der Look-Ahead und Look-Behind verwendet werden, um dies mit grep zu lösen.
Joachim Breitner

Sie können eine Gruppe aus einem Muster mit weitergeleiteten grep -oAufrufen extrahieren . stackoverflow.com/a/58314379/117471
Bruno Bronosky

12

Und für eine weitere Option würde ich mit awk gehen!

echo "foo bar <foo> bla 1 2 3.4" | awk '{ print $(NF-1), $NF; }'

Dadurch wird die Eingabe (ich verwende hier STDIN, aber Ihre Eingabe könnte leicht eine Datei sein) auf Leerzeichen aufgeteilt und dann das vorletzte Feld und dann das letzte Feld ausgedruckt. Das$NF Variablen enthalten die Anzahl der Felder, die nach dem Auflösen von Leerzeichen gefunden wurden.

Dies hat den Vorteil, dass es keine Rolle spielt, ob sich das, was den letzten beiden Feldern vorausgeht, ändert, solange Sie nur die letzten beiden Felder möchten, funktioniert es weiterhin.


3

Der Befehl cut ist genau für diese Situation ausgelegt. Es wird auf jedem Trennzeichen "geschnitten" und dann können Sie angeben, welche Chunks ausgegeben werden sollen.

Zum Beispiel: echo "foo bar <foo> bla 1 2 3.4" | cut -d " " -f 6-7

Wird zur Ausgabe von: 2 3.4

-d setzt das Trennzeichen

-f wählt den Bereich der auszugebenden 'Felder' aus. In diesem Fall ist dies der 6. bis 7. Block der ursprünglichen Zeichenfolge. Sie können den Bereich auch als Liste angeben, z 6,7.


Um nur bestimmte Spalten zu drucken, awk '{ print $2" "$6 }'
leiten Sie

@nurettin Ich denke, dein Kommentar könnte für eine der awk-Antworten gedacht sein.
carlin.scott

Ich habe versucht zu schneiden, als ich diese Seite besuchte und erkannte, dass es Einschränkungen gibt, und entschied mich, stattdessen eine allgemeinere Version in awk als Kommentar zu schreiben, um die Qualität dieses Beitrags zu verbessern.
Nurettin

1
Ja, ich denke, das gehört zu einer anderen Antwort, die awk betrifft. Der Befehl cut, um das zu tun, was Sie geschrieben haben, lautet:cut -d " " -f 2,6
carlin.scott

ah, das wusste ich nicht, ich dachte du könntest nur Bereiche geben. Dank dafür.
Nurettin

2

Ich stimme @kent zu, dass dies gut geeignet ist grep -o. Wenn Sie eine Gruppe innerhalb eines Musters extrahieren müssen, können Sie dies mit einem zweiten Grep tun.

# To extract \1 from /xx([0-9]+)yy/
$ echo "aa678bb xx123yy xx4yy aa42 aa9bb" | grep -Eo 'xx[0-9]+yy' | grep -Eo '[0-9]+'
123
4

# To extract \1 from /a([0-9]+)b/
$ echo "aa678bb xx123yy xx4yy aa42 aa9bb" | grep -Eo 'a[0-9]+b' | grep -Eo '[0-9]+'
678
9
Durch die Nutzung unserer Website bestätigen Sie, dass Sie unsere Cookie-Richtlinie und Datenschutzrichtlinie gelesen und verstanden haben.
Licensed under cc by-sa 3.0 with attribution required.