Regex Grep NÃO contendo string


182

Estou passando uma lista de padrões de regex greppara verificar em um arquivo syslog. Eles geralmente correspondem a um endereço IP e uma entrada de log;

grep "1\.2\.3\.4.*Has exploded" syslog.log

É apenas uma lista de padrões como a "1\.2\.3\.4.*Has exploded"parte que estou passando, em um loop, então não posso passar "-v" por exemplo.

Estou confuso ao tentar fazer o inverso do exposto acima, um NÃO corresponde a linhas com um determinado endereço IP e erro, de modo que "! 1.2.3.4. * Explosion" corresponderá às linhas do syslog para algo diferente de 1.2.3.4, informando que ele explodiu . I deve ser capaz de incluir um IP para não coincidem.

Eu já vi vários posts semelhantes no StackOverflor, no entanto, eles usam padrões regex com os quais não consigo trabalhar grep. Alguém pode dar um exemplo de trabalho, por grepfavor?

UPDATE: Isso está acontecendo em um script como este;

patterns[1]="1\.2\.3\.4.*Has exploded"
patterns[2]="5\.6\.7\.8.*Has died"
patterns[3]="\!9\.10\.11\.12.*Has exploded"

for i in {1..3}
do
 grep "${patterns[$i]}" logfile.log
done

Você quer dizer que às vezes deseja corresponder a um padrão, mas outras vezes deseja corresponder a tudo, exceto um determinado padrão? (isso parece um requisito estranho, mas tanto faz). Nesse caso, por que você não itera sobre duas listas diferentes de padrões?
Beerbajay

Bem, eu não tenho muito conhecimento sobre regex; Eu não quero grep para "Has Exploded" porque não quero saber isso sobre todos os dispositivos de registro, então posso de alguma forma grep para "Has Exploded" e! 9.10.11.12 em uma instrução?
Jwbensley

Se você absolutamente deve fazê-lo em uma afirmação, olhares negativos são o caminho a percorrer, como Neil sugere. Veja meu comentário lá.
Beerbajay

Use a correspondência de expressões regulares no estilo PCRE e uma declaração negativa, conforme a resposta de @Neil: as patterns[3]="\!9\.10\.11\.12.*Has exploded"alterações patterns[3]="(?<!9\.10\.11\.12).*Has exploded"e as grep "${patterns[$i]}" logfile.logalterações no grep -P "${patterns[$i]}" logfile.logPCRE assumem mais metacaracteres por padrão, portanto, algumas fugas podem precisar ser removidas de outras expressões correspondentes.
código é o seguinte

Respostas:


342

grepcorresponde, grep -vfaz o inverso. Se você precisa "combinar A, mas não B", normalmente usa tubos:

grep "${PATT}" file | grep -v "${NOTPATT}"

Isso está ocorrendo no meio de um loop, como mencionei, e estou passando o PATTERN para grep, para que não possa usar "-v" como mencionei. Estou apenas percorrendo uma lista de padrões e passando para grep.
Jwbensley #

1
Você pode realmente usar -ve pode usá-lo em um loop. Talvez você precise ser mais específico sobre suas limitações, ou talvez tenha um equívoco sobre como seu script deve funcionar. Tente postar algum código.
Beerbajay

Obrigado beerbajay, adicionei um código cortado à postagem original para dar algum contexto. Você entende o que eu quero dizer agora?
Jwbensley #

Esta resposta não está completamente correta, mas você estava escrevendo beerbajay, eu precisava repensar o loop e usar -v no final. Graças para o ponteiro;)
jwbensley

1
Mas e se A for composto de B? Em outras palavras, e se eu quiser combinar linhas sem A e linhas com AB? Um cano não vai funcionar.
pawamoy

15
(?<!1\.2\.3\.4).*Has exploded

Você precisa executar isso com -P para ter uma aparência negativa (expressão regular do Perl); portanto, o comando é:

grep -P '(?<!1\.2\.3\.4).*Has exploded' test.log

Tente isso. Ele usa lookbehind negativo para ignorar a linha, se for precedida por 1.2.3.4. Espero que ajude!


1
Tenho certeza de que grepisso não é compatível. A menos que você esteja usando o Gnu grepe use o --Pparâmetro para fazê-lo usar um mecanismo PCRE.
Tim Pietzcker

Não, o grep não suporta esse tipo de Regex; $ grep -P (? <\! 1 \ .2 \ .3 \ .4) test.log -bash: erro de sintaxe próximo ao token inesperado `('
jwbensley

Você precisará citar o regex se ele contiver caracteres que seriam interpretados pelo shell.
Beerbajay

citação correta: grep -P '(?<!1\.2\.3\.4) Has exploded' test.logObserve que o lookbehind funciona apenas nos caracteres imediatamente anteriores à parte correspondente da expressão; portanto, se houver outras coisas entre o endereço e a mensagem, por exemplo 1.2.3.4 FOO Has exploded, isso não funcionará.
Beerbajay

@TimPietzcker, muito observador. Vou acrescentar isso à pergunta. Além disso, observe que há um .*aspecto negativo depois que o exemplo dele também o possui, imagino que possa haver outro texto no meio.
Neil

2
patterns[1]="1\.2\.3\.4.*Has exploded"
patterns[2]="5\.6\.7\.8.*Has died"
patterns[3]="\!9\.10\.11\.12.*Has exploded"

for i in {1..3}
 do
grep "${patterns[$i]}" logfile.log
done

deve ser o mesmo que

egrep "(1\.2\.3\.4.*Has exploded|5\.6\.7\.8.*Has died)" logfile.log | egrep -v "9\.10\.11\.12.*Has exploded"    
Ao utilizar nosso site, você reconhece que leu e compreendeu nossa Política de Cookies e nossa Política de Privacidade.
Licensed under cc by-sa 3.0 with attribution required.