Estou tentando usar o grep para todas as instâncias de Ui\.
não seguido por Line
ou mesmo apenas a letraL
Qual é a maneira correta de escrever um regex para localizar todas as instâncias de uma determinada string NÃO seguida por outra string?
Usando lookaheads
grep "Ui\.(?!L)" *
bash: !L: event not found
grep "Ui\.(?!(Line))" *
nothing
regex
grep
regex-lookarounds
Lee Quarella
fonte
fonte
set +o histexpand
em Bash ouset +H
YMMV.Respostas:
Antecipação negativa, que é o que você procura, requer uma ferramenta mais poderosa do que o padrão
grep
. Você precisa de um grep habilitado para PCRE.Se você tem GNU
grep
, a versão atual suporta opções-P
ou--perl-regexp
e você pode usar o regex que deseja.Se você não tem (uma versão suficientemente recente do) GNU
grep
, considere obterack
.fonte
!
como um caractere especial.-P
não é suportado resultado tubulação tentar novamentegrep --invert-match
, ex:git log --diff-filter=D --summary | grep -E 'delete.*? src' | grep -E --invert-match 'xml'
. Certifique-se de votar positivamente na resposta de @Vinicius Ottoni.A resposta para parte do seu problema está aqui, e ack se comportaria da mesma maneira: Ack & lookahead negativo dando erros
Você está usando aspas duplas para grep, o que permite ao bash "interpretar
!
como comando de expansão de histórico".Você precisa envolver seu padrão em CITAÇÕES ÚNICAS:
grep 'Ui\.(?!L)' *
No entanto, consulte a resposta de @JonathanLeffler para resolver os problemas com antecipações negativas no padrão
grep
!fonte
grep
com a funcionalidade do padrãogrep
, onde o padrão paragrep
é POSIX. O que você diz também é verdade - executo o Bash com as barbáries do C-shell desativadas (porque se eu quisesse um C-shell, usaria um, mas não quero), então as!
coisas não me afetam - mas para obter antecipações negativas, você precisa do não padrãogrep
.Você provavelmente não pode executar lookaheads negativos padrão usando grep, mas normalmente você deve ser capaz de obter um comportamento equivalente usando a opção "inversa" '-v'. Usando isso, você pode construir um regex para o complemento do que deseja corresponder e, em seguida, canalizá-lo por meio de 2 greps.
Para a regex em questão, você pode fazer algo como
fonte
Se você precisa usar uma implementação de regex que não suporta lookaheads negativos e não se importa em combinar caracteres extras *, você pode usar classes de caracteres negados
[^L]
, alternância|
e âncora de fim de string$
.No seu caso
grep 'Ui\.\([^L]\|$\)' *
faz o trabalho.Ui\.
corresponde à string em que você está interessado\([^L]\|$\)
corresponde a qualquer caractere único diferente deL
ou corresponde ao final da linha:[^L]
ou$
.Se você quiser excluir mais do que apenas um caractere, basta lançar mais alternância e negação nele. Para encontrar
a
não seguido porbc
:grep 'a\(\([^b]\|$\)\|\(b\([^c]\|$\)\)\)' *
Que é (
a
seguido por nãob
ou seguido pelo final da linha:a
então[^b]
ou$
) ou (a
seguido porb
que é seguido por nãoc
ou é seguido pelo final da linha:a
entãob
, então[^c]
ou$
.Este tipo de expressão torna-se bastante pesado e sujeito a erros, mesmo com uma string curta. Você poderia escrever algo para gerar as expressões para você, mas provavelmente seria mais fácil usar apenas uma implementação de regex que suporte lookaheads negativos.
* Se sua implementação oferecer suporte a grupos de não captura , você pode evitar a captura de caracteres extras.
fonte
Se o seu grep não suporta -P ou --perl-regexp, e você pode instalar o grep habilitado para PCRE, por exemplo, "pcregrep", então ele não precisará de nenhuma opção de linha de comando como GNU grep para aceitar o padrão compatível com Perl expressões, você acabou de correr
Você não precisa de outro grupo aninhado para "Linha" como em seu exemplo "Ui. (?! (Linha))" - o grupo externo é suficiente, como mostrei acima.
Deixe-me dar outro exemplo de como procurar asserções negativas: quando você tem uma lista de linhas, retornada por "ipset", cada linha mostrando o número de pacotes no meio da linha, e você não precisa de linhas com pacotes zero, você apenas corre:
Se você gosta de expressões regulares compatíveis com perl e tem perl, mas não tem pcregrep ou seu grep não suporta --perl-regexp, você pode criar scripts perl de uma linha que funcionam da mesma maneira que grep:
Perl aceita stdin da mesma forma que grep, por exemplo
fonte