O GNU Grep pode gerar um grupo selecionado?

47

É possível usar o GNU grep para obter um grupo correspondente de uma expressão?

Exemplo:

echo "foo 'bar'" | grep -oE "'([^']+)'"

O que produziria "'bar'". Mas eu gostaria de obter apenas "barra", sem ter que enviá-lo através do grep mais uma vez (ou seja, obter o grupo correspondente). Isso é possível?

Torandi
fonte

Respostas:

50

Você pode usar sedpara isso. No BSD sed:

echo "foo 'bar'" | sed -E "s/.*'([^']+)'.*/\\1/"

Ou, sem a -Eopção:

sed "s/.*'\([^']\+\)'.*/\1/"

Isso não funciona para entrada de várias linhas. Para isso você precisa:

sed -n "s/.*'\([^']\+\)'.*/\1/p"
jtbandes
fonte
Obrigado, tinha esquecido sed. Mas para esclarecer, sed não toma o -E argumento ..
Torandi
Hum, isso acontece na minha máquina (Mac OS X). Após um exame mais aprofundado, na página de manual: "As opções -E, -a e -i são extensões não padrão do FreeBSD e podem não estar disponíveis em outros sistemas operacionais."
jtbandes
1
-r parece isso para mim.
Torandi
1
@ Jtbandes: Você não precisa dos recursos estendidos para esta expressão .. Eu só requer 3 caracteres de escape para ( ) +uso \( \) \+: Este é efetivamente o mesmo:sed "s/.*'\([^']\+\)'.*/\1/"
Peter.O
2
Isso não funciona para entrada de várias linhas. Para isso você precisa: sed -n "s/.*'\([^']\+\)'.*/\1/p"
phreakhead
28

Enquanto o grep não pode gerar um grupo específico, você pode usar as declarações lookahead e behind para obter o que quer depois:

echo "foo 'bar'" | grep -Po "(?<=')[^']+(?=')"

Aldrik
fonte
8
grep -Pnão está disponível em todas as plataformas. Mas, se estiver, usar lookahead / behind é uma maneira muito boa de resolver o problema.
Sébastien
1
O grep é inteligente com as asserções de look-behind? Como ele funciona com look-behinds longos? É integrar os olhares atrás em algum tipo de "árvore de sufixos" com o resto da regex?
Ross Rogers
3

Você pode usar \Kpara redefinir e descartar o texto da correspondência à esquerda, juntamente com um cabeçote que não seja adicionado ao texto da correspondência:

$ echo "foo 'bar'" | grep -oP "'\K[^']+(?=')"
bar

Somente GNU grep.

drewk
fonte