Digamos que eu tenho um arquivo:
# file: 'test.txt'
foobar bash 1
bash
foobar happy
foobar
Eu só quero saber quais palavras aparecem depois de "foobar", para que eu possa usar este regex:
"foobar \(\w\+\)"
Os parênteses indicam que tenho um interesse especial pela palavra logo após foobar. Mas quando eu faço a grep "foobar \(\w\+\)" test.txt
, recebo as linhas inteiras que correspondem a toda a expressão regular, em vez de apenas "a palavra após foobar":
foobar bash 1
foobar happy
Eu preferiria muito que a saída desse comando fosse assim:
bash
happy
Existe uma maneira de dizer ao grep para emitir apenas os itens que correspondem ao agrupamento (ou a um agrupamento específico) em uma expressão regular?
text-processing
grep
regular-expression
Cory Klein
fonte
fonte
perl -lne 'print $1 if /foobar (\w+)/' < test.txt
Respostas:
O GNU grep tem a
-P
opção de expressões regulares no estilo perl e a-o
opção de imprimir apenas o que corresponde ao padrão. Eles podem ser combinados usando asserções de pesquisa (descritas em Padrões estendidos na página de manual do perlre ) para remover parte do padrão grep do que é determinado ter correspondido para os fins de-o
.O
\K
é o formato abreviado (e mais eficiente)(?<=pattern)
que você usa como uma declaração de look-behind de largura zero antes do texto que deseja produzir.(?=pattern)
pode ser usado como uma afirmação antecipada de largura zero após o texto que você deseja gerar.Por exemplo, se você deseja combinar a palavra entre
foo
ebar
, você pode usar:ou (por simetria)
fonte
sed(1)
grep -oP 'foobar \K\w+' test.txt
nada produz com os OP'stest.txt
. A versão grep é 2.5.1. O que pode estar errado ? O_OO grep padrão não pode fazer isso, mas as versões recentes do GNU grep podem . Você pode mudar para sed, awk ou perl. Aqui estão alguns exemplos que fazem o que você deseja na sua entrada de amostra; eles se comportam de maneira ligeiramente diferente nos cantos.
Substitua
foobar word other stuff
porword
, imprima apenas se uma substituição for concluída.Se a primeira palavra for
foobar
, imprima a segunda palavra.Retire
foobar
se for a primeira palavra e pule a linha caso contrário; depois retire tudo após o primeiro espaço em branco e imprima.fonte
grep
. Mas a sintaxe para esses comandos realmente parece muito familiar agora que estou familiarizado com a pesquisa e substituição de expressões no estilo vim. Muito obrigado.grep
não possui suporte para PCRE.fonte
^
e$
são estranhos, pois.*
é uma combinação gananciosa. No entanto, incluí-los pode ajudar a esclarecer a intenção da regex.Bem, se você souber que foobar é sempre a primeira palavra ou a linha, use cortada. Igual a:
fonte
-o
ativação do grep é amplamente implementada (mais do que as extensões grep do Gnu), ogrep -o "foobar" test.file | cut -d" " -f2
que aumentará a eficácia dessa solução, que é mais portátil do que usar asserções ocultas.grep -o "foobar .*
"ougrep -o "foobar \w+"
.Se o PCRE não for suportado, você poderá obter o mesmo resultado com duas invocações do grep. Por exemplo, para pegar a palavra após foobar, faça o seguinte:
Isso pode ser expandido para uma palavra arbitrária após foobar como este (com EREs para facilitar a leitura):
Resultado:
Observe que o índice
i
é baseado em zero.fonte
pcregrep
possui uma-o
opção mais inteligente que permite escolher quais grupos de captura você deseja exibir. Então, usando seu arquivo de exemplo,fonte
O uso
grep
não é compatível com várias plataformas, pois-P
/--perl-regexp
está disponível apenas no GNUgrep
, não no BSDgrep
.Aqui está a solução usando
ripgrep
:Conforme
man rg
:Palavras-chave : GH-462 .
fonte
Achei a resposta de @jgshawkey muito útil.
grep
não é uma ferramenta tão boa para isso, mas sed é, embora aqui tenhamos um exemplo que usa grep para pegar uma linha relevante.A sintaxe da regex do sed é idiossincrática se você não estiver acostumado.
Aqui está outro exemplo: este analisa a saída do xinput para obter um número inteiro de ID
e eu quero 19
Observe a sintaxe da classe:
e a necessidade de escapar do seguinte
+
Presumo que apenas uma linha corresponda.
fonte
grep
, assumindo que 'TouchPad' está à esquerda de 'id':echo "SynPS/2 Synaptics TouchPad id=19 [slave pointer (2)]" | sed -nE "s/.*TouchPad.+id=([0-9]+).*/\1/p"