sed Capture-Gruppen funktionieren nicht

27

Ich habe eine Zeichenfolge des Formats [0-9]+\.[0-9]+\.[0-9]. Ich muss die erste, zweite und dritte Zahl separat extrahieren. Soweit ich weiß, sollten Fanggruppen dazu in der Lage sein. Ich sollte in der Lage sein sed "s/\([0-9]*\)/\1/g, die erste Nummer sed "s/\([0-9]*\)/\2/gzu bekommen, die zweite Nummer sed "s/\([0-9]*\)/\3/gzu bekommen und die dritte Nummer zu bekommen. In jedem Fall bekomme ich aber die ganze Saite. Warum passiert dies?

Melab
quelle
6
Gruppen erfassen erfasst die gesamte Gruppe ... nicht einzelne Elemente in der Gruppe. Sie brauchen so etwas wie 's/\([0-9]\)\([0-9]\)\([0-9]\).*/\1\2\3/'einzelne Nummern zu erfassen.
Munir

Antworten:

44

Ohne ein Beispiel für Ihre Eingabe können wir Ihnen keine vollständige Antwort geben, aber ich kann Ihnen sagen, dass Ihr Verständnis von Erfassungsgruppen falsch ist. Sie werden nicht nacheinander verwendet, sondern beziehen sich nur auf den regulären Ausdruck auf der linken Seite desselben Substitutionsoperators. Wenn Sie zum Beispiel einfangen, /(foo)(bar)(baz)/dann foowird \1, barwird \2und bazwird es sein \3. Dies ist nicht möglich s/(foo)/\1/; s/(bar)/\2/, da beim zweiten s///Aufruf nur eine erfasste Gruppe vorhanden ist und daher \2nicht definiert wird.

Um also Ihre drei Zifferngruppen zu erfassen, müssten Sie Folgendes tun:

sed 's/\([0-9]*\)\.\([0-9]*\)\.\([0-9]*\)/\1 : \2 : \3/'

Oder je besser lesbar:

sed -E 's/([0-9]*)\.([0-9]*)\.([0-9]*)/\1 : \2 : \3/'
terdon
quelle
1
Was bringt es, wenn Sie im ersten Beispiel die Klammern schließen?
Josh M.
2
@JoshM. Sie müssen ihnen entkommen, damit sie zum Erfassen von Mustern verwendet werden können. Normalerweise entspricht /(foo)/sed einem wörtlichen (Zeichen, gefolgt von fooeinem wörtlichen ). Wenn Sie eine Gruppe erfassen möchten, müssen Sie entweder die Klammern schließen oder die -EOption verwenden.
Terdon
Ich benutze fast immer die -rFlagge, daher gehe ich davon aus, dass ich noch nicht darauf gestoßen bin.
Josh M.
1
@JoshM. Ja, die -rFlagge macht das auch, ist aber nicht portabel. GNU sed unterstützt es, aber viele andere nicht. Das -Eist universeller.
terdon
9

Beispiel:

$ echo "123.456.78" |sed 's/\([0-9]*\)\.\([0-9]*\)\.\([0-9]*\)/\1/'
123

$ echo "123.456.78" |sed 's/\([0-9]*\)\.\([0-9]*\)\.\([0-9]*\)/\2/'
456

$ echo "123.456.78" |sed 's/\([0-9]*\)\.\([0-9]*\)\.\([0-9]*\)/\3/'
78

Oder alles zusammen:

$ echo "123.456.78" |sed 's/\([0-9]*\)\.\([0-9]*\)\.\([0-9]*\)/\1 : \2 : \3/'
123 : 456 : 78
jai_s
quelle
2

Verwenden Sie Sed mit -r, --regexp-extended, um alle ausgeblendeten Klammern zu vermeiden.

echo "1234.567.89" | sed -r 's/([0-9]+)\.([0-9]+)\.([0-9]+)/\1, \2, \3/' 
1234, 567, 89    #output
Surya
quelle