Stampa una riga solo se la riga successiva NON contiene una corrispondenza specifica


12

Sto cercando di cercare un file di registro per le attività registrate che non sono state completate. Ad esempio, registro un'attività "Avvio per ID 1234 ..." e, in caso di successo, la riga successiva sarà "Attività 1234 completata".

Sto cercando di ottenere le righe "Inizio ..." che NON sono seguite dalle corrispondenti righe "Completate".

File di registro di esempio

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

In questo esempio, cercherò che l'output sia:

Starting activity for ID 33367

... perché non è seguito da una riga "completata".

Ho provato a farlo con grepe awk, ma non ho avuto molto successo. Suppongo che possa essere fatto con uno di quegli strumenti, ma mio grepe awkbraciole non sono avanzati.

Alla ricerca di un modello rapido e affidabile grepo awkper dare i risultati di cui ho bisogno qui.


Non credo sia facile con grep + awk, ma puoi spiegarci un po 'perché lo stai facendo? Un risultato di tutte le attività in corso, ad es. Successo o non finanziato?
margherita,

@ warl0ck, sto cercando il "non finito".
PattMauler,

Risposte:


10

Ecco awkun'alternativa:

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

Produzione:

Starting activity for ID 33367

La Imatrice associativa tiene traccia di ciò che gli ID sono stati visti.


Funziona davvero bene, dato che sembra anche adattarsi a situazioni in cui le linee di registro "Avvio ..." e "Completato ..." non sono adiacenti / sequenziali. Grazie @Thor!
PattMauler,

Prego. Questo dovrebbe funzionare in modo efficiente con input di dimensioni (quasi) arbitrarie in quanto memorizza sempre l'ID e il tempo di ricerca è O (1).
Thor,

Bello. Solo una cosa: come ho appreso da @RobertL ( unix.stackexchange.com/a/243550/135943 ) non è necessario assegnare un valore per creare un elemento array. Quindi, invece di I[$5] = 1, puoi semplicemente usare I[$5]. (Non ti interessa il valore, vuoi solo far esistere l'elemento , e semplicemente nominarlo lo compie.)
Wildcard

@Wildcard: hai ragione, ma dopo aver esaminato la domanda del PO e il grep come l'output che sta cercando, è più appropriato ricordare l'intera riga e output che alla fine.
Thor,

3
sed '$!N;/\n.*completed/d;P;D' <input

Ciò eliminerà dall'output tutte le righe di input che non sono seguite da una riga corrispondente alla stringa completata .


2

Ecco come puoi farlo con GNU sed:

sed -r 'N; /([0-9]+)\n\w+\s+\1/d; P; D' infile
  • N legge un'altra riga nello spazio modello.
  • La regex di corrispondenza verifica se vengono trovati ID identici, se viene eliminato lo spazio modello ( d) e il ciclo viene riavviato.
  • Se non corrisponde, stampa la prima riga nello spazio modello ( P) ed eliminala ( D).

Non riesco a vedere nulla esteso qui ... quindi -rnon è necessario, giusto?
Louis Maddox,

1
@lmmx: è necessario perché altrimenti il ​​gruppo di acquisizione deve essere evaso e lo stesso vale per il +quantificatore.
Thor,

Ah ok! L'ho modificato e mi è stato detto che non era necessario, grazie per il chiarimento
Louis Maddox,

1

se l'installazione supporta pcregrep, l'opzione multilinea (-M) è utile.

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

Avvio dell'attività per ID 33367

Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.