Grep regex NO contiene cadena

182

Estoy pasando una lista de patrones regex greppara verificar en un archivo syslog. Por lo general, coinciden con una dirección IP y una entrada de registro;

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

Es solo una lista de patrones como la "1\.2\.3\.4.*Has exploded"parte que estoy pasando, en un bucle, por lo que no puedo pasar "-v" por ejemplo.

Estoy confundido tratando de hacer lo contrario de lo anterior, un NO coincide con las líneas con una determinada dirección IP y error, por lo que "! 1.2.3.4. * Ha explotado" coincidirá con las líneas de syslog para cualquier cosa que no sea 1.2.3.4 diciéndome que ha explotado . Yo debo ser capaz de incluir una IP a no coinciden.

He visto varias publicaciones similares en StackOverflor, sin embargo, usan patrones de expresiones regulares con las que parece que no puedo trabajar grep. ¿Alguien puede proporcionar un ejemplo de trabajo por grepfavor?

ACTUALIZACIÓN: Esto está sucediendo en un 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
jwbensley
fuente
¿Quiere decir que a veces quiere hacer coincidir un patrón, pero otras veces quiere hacer coincidir todo excepto un cierto patrón? (Esto parece un requisito extraño, pero lo que sea). En ese caso, ¿por qué no itera sobre dos listas diferentes de patrones?
beerbajay
Bueno, no estoy muy bien informado sobre expresiones regulares; No quiero buscar "Ha explotado" porque no quiero saber esto acerca de todos los dispositivos de registro, entonces, ¿puedo de alguna manera buscar "Ha explotado" y! 9.10.11.12 en una sola declaración?
jwbensley
Si absolutamente debe hacerlo en una declaración, las miradas negativas son el camino a seguir, como sugiere Neil. Mira mi comentario allí.
beerbajay
Use la coincidencia de expresiones regulares de estilo PCRE y una afirmación anticipada negativa, según la respuesta de @Neil: los patterns[3]="\!9\.10\.11\.12.*Has exploded"cambios patterns[3]="(?<!9\.10\.11\.12).*Has exploded"y los grep "${patterns[$i]}" logfile.logcambios en grep -P "${patterns[$i]}" logfile.logPCRE asumen más metacaracteres de forma predeterminada, por lo que algunos de los escapes pueden necesitar eliminarse de otras expresiones coincidentes.
Codex24

Respuestas:

342

grepcoincide, grep -vhace lo contrario. Si necesita "hacer coincidir A pero no B", generalmente usa tuberías:

grep "${PATT}" file | grep -v "${NOTPATT}"
Beerbajay
fuente
Esto está yendo a la mitad de un bucle como mencioné y solo estoy pasando el PATRÓN a grep para que no pueda usar "-v" como mencioné. Solo estoy dando vueltas alrededor de una lista de PATRONES y pasando a grep.
jwbensley
1
De hecho, puede usar -vy puede usarlo en un bucle. Quizás necesite ser más específico acerca de sus limitaciones, o quizás tenga una idea errónea sobre cómo debería funcionar su script. Intenta publicar un código.
beerbajay
Gracias beerbajay, he agregado un código recortado a la publicación original para darle un poco de contexto. ¿Ves lo que quiero decir ahora?
jwbensley
Esta respuesta no es completamente correcta, pero estabas prácticamente escribiendo beerbajay, necesitaba repensar el ciclo y usar -v al final. Gracias por el puntero;)
jwbensley
1
Pero, ¿y si A está compuesto de B? En otras palabras, ¿qué pasa si quiero unir líneas sin A y líneas con AB? Una tubería no funcionará.
pawamoy
15
(?<!1\.2\.3\.4).*Has exploded

Debe ejecutar esto con -P para tener una mirada negativa hacia atrás (expresión regular de Perl), por lo que el comando es:

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

Prueba esto. Utiliza una mirada hacia atrás negativa para ignorar la línea si está precedida por 1.2.3.4. ¡Espero que ayude!

Neil
fuente
1
Estoy bastante seguro de que eso grepno es compatible con la búsqueda. A menos que esté usando Gnu grepy use el --Pparámetro para que use un motor PCRE.
Tim Pietzcker
No, grep no admite este tipo de expresiones regulares; $ grep -P (? <\! 1 \ .2 \ .3 \ .4) test.log -bash: error de sintaxis cerca de token inesperado `('
jwbensley
Tendrá que citar la expresión regular si contiene caracteres que serían interpretados por el shell.
beerbajay
cita correcta: grep -P '(?<!1\.2\.3\.4) Has exploded' test.logtenga en cuenta que el aspecto posterior solo funciona en los caracteres que preceden inmediatamente a la parte coincidente de la expresión, por lo que si hay otras cosas entre la dirección y el mensaje, por ejemplo 1.2.3.4 FOO Has exploded, esto no funcionará.
beerbajay
@TimPietzcker, muy observador. Agregaré eso a la pregunta. Además, tenga en cuenta que hay una .*mirada negativa posterior, ya que su ejemplo también lo tiene, imagino que podría haber otro texto en el medio.
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

debería ser lo mismo que

egrep "(1\.2\.3\.4.*Has exploded|5\.6\.7\.8.*Has died)" logfile.log | egrep -v "9\.10\.11\.12.*Has exploded"    
krecker
fuente