Estoy analizando un archivo de buzón que almacena informes del servidor de correo electrónico en busca de correos electrónicos entregados sin éxito. Deseo extraer direcciones de correo electrónico incorrectas, por lo que que los elimino del sistema. El archivo de registro se ve así:

...some content... The mail system <[email protected]>: host mx1.hotmail.com[65.54.188.94] said: 550 Requested action not taken: mailbox unavailable (in reply to RCPT TO command) ...some content... The mail system <[email protected]>: host viking.optimumpro.net[79.101.51.82] said: 550 Unknown user (in reply to RCPT TO command) ...some content... The mail system <[email protected]>: host mta5.am0.yahoodns.net[74.6.140.64] said: 554 delivery error: dd This user doesn"t have a yahoo.com account ([email protected]) [0] - mta1172.mail.sk1.yahoo.com (in reply to end of DATA command) ...etc. 

La dirección de correo electrónico viene 2 líneas después de una línea con «El sistema de correo» . El uso de grep de esta manera me da la línea «El sistema de correo» y las siguientes dos líneas:

grep -A 2 "The mail system" mbox_file 

Sin embargo, no sé cómo eliminar el Línea «El sistema de correo» y la segunda línea vacía de esta salida. Supongo que podría escribir un script PHP / Perl / Python para hacerlo, pero me pregunto si esto es posible con grep o alguna otra herramienta estándar. Intenté dar un desplazamiento negativo al parámetro -B:

grep -A 2 -B -2 "The mail system" mbox_file 

Pero grep se queja:

grep: -2: invalid context length argument 

¿Hay alguna forma de hacer esto con grep?

Comentarios

  • -B acepta numerales como lo haría -A, y mostraría el líneas anteriores antes del partido.
  • Sí, eso es cierto, pero Milán no está ‘ t interesado en lo que precede al partido .. . El problema que encontró es que -A y -B solo aceptan valores positivos … y que, en cualquier caso, -A y -B no pueden ‘ t ser usados entre sí , como ha intentado hacer.
  • Hum, solo para asegurarse: esas son direcciones ficticias que no extrajo (directamente) del archivo que le dieron, ¿verdad?
  • @Matthieu M. no, son de un archivo de registro real. Supuse que, dado que de todos modos son direcciones no válidas, ‘ es el objetivo de inventar direcciones ficticias que podrían ser válidas.
  • stackoverflow.com/questions/8101701/…

Respuesta

La forma más sencilla de resolverlo usando grep solamente, es canalizar una grep invertida más al final . Por ejemplo:

grep -A 4 "The mail system" temp.txt | grep -v "The mail system" | grep -v "^\d*$" 

Responder

Si no está encerrado en utilizando grep, intente sed

sed -n "/The mail system/{n;n;p}" 

Cuando encuentra una línea que contiene «El sistema de correo», lee la siguiente línea dos veces, a través de n;n;, descartando cada línea anterior mientras lo hace.
Esto deja la tercera línea de su grupo en el espacio del patrón, que luego se imprime mediante el comando sed «s p .. La opción -n inicial evita todas las demás impresiones .

Para imprimir las siguientes dos líneas también, es solo un caso de siguiente e imprimir n;p dos veces más.

sed -n "/The mail system/{n; n;p; n;p; n;p}" 

Las lecturas de la siguiente línea para las líneas que necesita se pueden acumular e imprimir en un solo bloque con solo un pN lee la siguiente línea y la agrega al espacio del patrón,

Aquí está la versión condensada final …

sed -n "/The mail system/{n;n;N;N;p}" 

Si desea un separador de grupo , similar al que generaría grep, puede usar el comando sed «s insert i (que debe ser el último comando en una línea) …

Aquí está la sintaxis para incluir un separador de grupo

sed -n "/The mail system/{n;n;N;N;p;i-- }" > output-file # or | ... 

Aquí está el resultado de la primera coincidencia:

<[email protected]>: host mx1.hotmail.com[65.54.188.94] said: 550 Requested action not taken: mailbox unavailable (in reply to RCPT TO command) -- 

Comentarios

  • +1. Gracias. No ‘ no lo necesito en este caso, pero ‘ mantendré esto marcado en caso de que tenga cosas más complicadas de manejar.
  • ¡Esta es una gran respuesta!

Respuesta

grep -A 2 -B -2 "The mail system" mbox_file 

-B es para líneas anteriores, por lo que no es necesario dar un valor -negativo.

grep -A 2 -B 2 "The mail system" mbox_file # This will work please check 

Comentarios

  • Esto no responde a la pregunta. -A 2 -B 2 imprime desde dos líneas antes del contexto hasta 2 líneas después del contexto. La pregunta se trata de imprimir de 2 líneas después del contexto a 4 líneas después del contexto.

Respuesta

I no tiene sentido usar solo grep (s), excepto si esa es una restricción estricta. No se puede hacer con una llamada a grep.

grep -A 2 "The mail system" mbox_file | tail -n +3 
  • grep: Encuentra la línea y muestra 2 líneas después,
  • tail: corta las primeras 2 líneas (es decir, comienza desde la tercera línea).

Comentarios

  • Esto solo funciona si hay una sola línea coincidente, que probablemente no sea lo que pregunta la pregunta.
  • Eso no es nada de lo que pidió la pregunta, pero me ayuda en mi situación actual :-).
  • @ daniel.neumann Lo sé, pero estaba exactamente en tu lugar y pensé que otros ‘ Google-fu llevar aquí también.

Respuesta

Si desea eliminar las primeras 2 líneas, envíelo a sed

sed "1,2d" 

como en

 grep -A 2 "The mail system" mbox_file | sed "1,2d"  

Comentarios

  • Se ha perdido el hecho de que el patrón ocurre muchas veces. Si aparece “El sistema de correo” en las líneas 4, 14, 24, 34,…, el OP quiere ver las líneas 6, 16, 26, 36,… Su respuesta dará 6, 14-16, 24-26, 34- 36,….

Respuesta

Esto imprime la siguiente línea después de la coincidencia de expresiones regulares, usando Perl

perl -ne "print if( (/The mail system/ && ($end=1))..!$end-- )" 

Deja una respuesta

Tu dirección de correo electrónico no será publicada. Los campos obligatorios están marcados con *