Regex correto não está funcionando no grep

13

Eu tenho este regex:

(?<=prefix).*$

que retorna qualquer caractere após a sequência "prefix" e funciona bem em qualquer mecanismo de regex online (por exemplo, https://regex101.com ). O problema é quando eu uso esse regex no bash:

grep '(?<=prefix).*$' <<< prefixSTRING

não corresponde a nada. Por que esse regex não funciona com grep?

mark009
fonte
11
Isso realmente destaca por que o regex101 precisa de um seletor de sabor POSIX da mesma forma que para JS, Perl / PHP e Python. Não posso contar o número de vezes que desejei por isso.
Jared Smith
Além disso, .*$corresponde a qualquer sequência até o final da linha (ou final da sequência), não apenas um caractere.
22919 ilkkachu

Respostas:

38

Você parece ter definido o regex certo, mas não definiu os sinalizadores suficientes na linha de comando greppara entendê-lo. Porque, por padrão, grepsuporta BRE e com -Eflag, ERE. O que você tem (olhar para o futuro) está disponível apenas no sabor regex PCRE, que é suportado apenas no GNU grepcom seu -Psinalizador.

Supondo que você precise extrair apenas a sequência correspondente depois prefixde adicionar um sinalizador extra -opara informar grepque imprime apenas a parte correspondente como

grep -oP '(?<=prefix).*$' <<< prefixSTRING

Há também uma versão grepque suporta bibliotecas PCRE por padrão - pcregrepna qual você pode fazer

pcregrep -o '(?<=prefix).*$' <<< prefixSTRING

Explicações detalhadas sobre vários tipos de expressões regulares são explicadas nesta maravilhosa resposta e ferramentas de Giles que implementam cada uma delas

Inian
fonte
38

Expressões regulares vêm em muitos sabores diferentes. O que você está mostrando é uma expressão regular do tipo Perl (PCRE, "Expressão regular compatível com Perl").

grepfaz expressões regulares POSIX. Essas são expressões regulares básicas (BRE) e expressões regulares estendidas (ERE, se grepusadas com a -Eopção). Consulte o manual para re_formatou regexou qualquer outra coisa semelhante manual do seu grepmanual refere-se em seu sistema, ou os textos padrão POSIX que eu só vinculados.

Se você usa o GNU grep, seria capaz de usar expressões regulares do tipo Perl se usasse grepcom a opção grepespecífica do GNU -P.

Observe também que grepretorna linhas por padrão, não substrings de linhas. Novamente, com o GNU grep(e algumas outras grepimplementações), você pode usar a -oopção para obter apenas os bits que correspondem à expressão especificada de cada linha.

Observe que as extensões -Pe -onão-padrão são a especificação POSIX degrep .

Se você não estiver usando o GNU grep, poderá usar sedpara obter o bit entre a string prefixe o final da linha:

sed -n 's/.*prefix\(.*\)/\1/p' file

O que isso faz é imprimir apenas as linhas que sedconseguem aplicar a substituição fornecida. A substituição substituirá a linha inteira que corresponder à expressão (que é um BRE), pela parte que ocorrer após a sequência prefix.

Observe que, se houver várias instâncias de prefixuma linha, a sedvariação retornará a sequência após a última , enquanto a grepvariação GNU retornará a sequência após a primeira (que incluiria as outras instâncias de prefix).

A sedsolução seria portátil para todos os sistemas do tipo Unix.

Kusalananda
fonte
6

Como as outras respostas declararam, grepnão usa um sabor de expressão regular com lookbehinds (por padrão no GNU grep, ou de modo algum com outras versões).

Se você não conseguir usar o GNU grepou pcregrep, poderá usá- perllo, se o tiver.

A linha de comando equivalente a perlseria:

perl -ne 'print if /(?<=prefix).*$/' <<< prefixSTRING

Você coloca a regex desejada entre as barras. Como você está usando Perl, isso usa o sabor regex do Perl .

quantum
fonte
ou print "$&\n" if ...se eles querem a saída apenas a parte após oprefix
ilkkachu