Imprima una línea solo si la siguiente línea NO contiene una coincidencia particular

12

Estoy intentando buscar en un archivo de registro las actividades registradas que no se completaron. Por ejemplo, registro una "Actividad de inicio para ID 1234 ..." y si tiene éxito, la siguiente línea será "Actividad 1234 completada".

Estoy tratando de obtener las líneas "Iniciando ..." que NO son seguidas por sus correspondientes líneas "Completadas".

Archivo de registro de ejemplo

Starting activity for ID 1234
ID 1234 completed successfully
Starting activity for ID 3423
ID 3423 completed successfully
Starting activity for ID 9876
ID 9876 completed successfully
Starting activity for ID 99889
ID 99889 completed successfully
Starting activity for ID 10011
ID 10011 completed successfully
Starting activity for ID 33367
Starting activity for ID 936819
ID 936819 completed successfully

En este ejemplo, estaría buscando que la salida sea:

Starting activity for ID 33367

... porque no es seguido por una línea "completada".

He intentado hacer esto con grepy awk, pero no he tenido mucho éxito. Supongo que se puede hacer con una de esas herramientas, pero my grepand awkchops no están avanzados.

En busca de una rápida y fiable grepo awkpatrón para dar los resultados que necesito aquí.

PattMauler
fuente
No creo que sea fácil con grep + awk, pero ¿puedes explicar un poco sobre por qué lo haces? ¿Un resultado de todas las actividades en ejecución, por ejemplo, exitoso o no?
margarita
@ warl0ck, estoy buscando el "no terminado".
PattMauler

Respuestas:

10

Aquí hay una awkalternativa:

awk '
  /^Starting/ { I[$5] = $0                  }
  /^ID/       { delete I[$2]                }
  END         { for (key in I) print I[key] }
' infile

Salida:

Starting activity for ID 33367

La Imatriz asociativa realiza un seguimiento de los identificadores que se han visto.

Thor
fuente
Esto funciona muy bien, ya que incluso parece acomodar situaciones donde las líneas de registro "Iniciando ..." y "Completado ..." no son adyacentes / secuenciales. Gracias @Thor!
PattMauler
De nada. Esto debería funcionar de manera eficiente con una entrada de tamaño (casi) arbitraria, ya que solo almacena el ID y el tiempo de búsqueda es O (1).
Thor
Agradable. Solo una cosa: como aprendí de @RobertL ( unix.stackexchange.com/a/243550/135943 ) no necesita asignar un valor para crear un elemento de matriz. Entonces, en lugar de I[$5] = 1, solo puedes usar I[$5]. (No le importa el valor, solo quiere hacer que el elemento exista , y simplemente nombrarlo logra eso).
Comodín el
@Wildcard: Tiene razón, pero después de revisar la pregunta del OP y el resultado grep como el que está buscando, es más apropiado recordar toda la línea y la salida al final.
Thor
3
sed '$!N;/\n.*completed/d;P;D' <input

Esto eliminará de la salida todas las líneas de entrada que no estén seguidas por una línea que coincida con la cadena completada .

mikeserv
fuente
2

Así es como podría hacerlo con GNU sed:

sed -r 'N; /([0-9]+)\n\w+\s+\1/d; P; D' infile
  • N lee una línea más en el espacio del patrón.
  • La coincidencia de expresiones regulares verifica si se encuentran identificadores idénticos, de ser así, se elimina el espacio del patrón ( d) y se reinicia el ciclo.
  • Si no coincide, imprima la primera línea en el espacio del patrón ( P) y elimínelo ( D).
Thor
fuente
No puedo ver nada extendido aquí ... así -rque no es necesario, ¿verdad?
Louis Maddox
1
@lmmx: es necesario porque de lo contrario el grupo de captura debe escapar, y lo mismo ocurre con el +cuantificador.
Thor
Ah ok! Lo modifiqué y me dijeron que no era necesario, gracias por aclararlo
Louis Maddox
1

Si su instalación admite pcregrep, la opción multilínea (-M) es útil.

pcregrep -M -o '\AStarting activity for ID (\d+)\n(?!ID \1)' t.z

Inicio de actividad para ID 33367

iruvar
fuente