grupos de captura sed não estão funcionando

27

Eu tenho uma sequência do formato [0-9]+\.[0-9]+\.[0-9]. Preciso extrair os primeiro, segundo e terceiro números separadamente. Pelo que entendi, os grupos de captura devem ser capazes disso. Eu deveria ser capaz de usar sed "s/\([0-9]*\)/\1/gpara obter o primeiro número, sed "s/\([0-9]*\)/\2/gobter o segundo número e sed "s/\([0-9]*\)/\3/gobter o terceiro número. Em cada caso, porém, estou recebendo toda a string. Por que isso está acontecendo?

Melab
fonte
6
Grupos de captura capturam o grupo inteiro ... não elementos individuais no grupo. Você precisa de algo como 's/\([0-9]\)\([0-9]\)\([0-9]\).*/\1\2\3/'capturar números individuais.
Munir 16/02

Respostas:

45

Não podemos fornecer uma resposta completa sem um exemplo de sua opinião, mas posso dizer que sua compreensão dos grupos de captura está errada. Você não os usa sequencialmente, eles se referem apenas à regex no lado esquerdo do mesmo operador de substituição. Se você capturar, por exemplo,, /(foo)(bar)(baz)/então fooserá \1, barserá \2e bazserá \3. Você não pode fazer isso s/(foo)/\1/; s/(bar)/\2/porque, na segunda s///chamada, há apenas um grupo capturado, portanto \2não será definido.

Portanto, para capturar seus três grupos de dígitos, você precisaria:

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

Ou, quanto mais legível:

sed -E 's/([0-9]*)\.([0-9]*)\.([0-9]*)/\1 : \2 : \3/'
terdon
fonte
1
Qual é o benefício de escapar dos parênteses no primeiro exemplo?
Josh M.
2
@JoshM. você precisa escapar deles para que eles sejam usados ​​para capturar padrões. Normalmente /(foo)/no sed irá corresponder a um (caractere literal , seguido por fooe, em seguida, um literal ). Se você deseja capturar um grupo, precisa escapar dos parênteses ou usar a -Eopção
terdon
Eu quase sempre uso a -rbandeira, então presumo que seja por isso que ainda não deparei com isso.
Josh M.
1
@JoshM. Sim, a -rbandeira também fará isso, mas não é portátil. O GNU sed suporta, mas muitos outros não. O -Eé mais universal.
terdon
9

Exemplo:

$ 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

Ou, todos juntos:

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

Use Sed com -r, --regexp-extended para evitar todos os parênteses escapados.

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