Imprimer une ligne uniquement si la ligne suivante ne contient PAS de correspondance particulière

12

J'essaie de rechercher dans un fichier journal des activités enregistrées qui ne se sont pas terminées. Par exemple, j'enregistre une "Activité de démarrage pour l'ID 1234 ..." et en cas de succès, la ligne suivante sera "Activité 1234 terminée".

J'essaye d'obtenir les lignes "Starting ..." qui ne sont PAS suivies de leurs lignes "Completed" correspondantes.

Exemple de fichier journal

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

Dans cet exemple, je rechercherais que la sortie soit:

Starting activity for ID 33367

... car il n'est pas suivi d'une ligne "terminée".

J'ai essayé de faire cela avec grepet awk, mais je n'ai pas eu beaucoup de succès. Je suppose que cela peut être fait avec l'un de ces outils, mais mes grepet awkcôtelettes ne sont pas avancés.

Vous cherchez un rapide et fiable grepou awkmodèle pour donner les résultats dont j'ai besoin ici.

PattMauler
la source
Je ne pense pas que ce soit facile avec grep + awk, mais pouvez-vous expliquer un peu pourquoi vous faites ça? Un résultat de toutes les activités en cours, par exemple le succès ou non terminé?
daisy
@ warl0ck, je cherche le "pas fini".
PattMauler

Réponses:

10

Voici une awkalternative:

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

Production:

Starting activity for ID 33367

Le Itableau associatif garde une trace des identifiants qui ont été vus.

Thor
la source
Cela fonctionne très bien, car il semble même s'adapter aux situations dans lesquelles les lignes de journal "Démarrage ..." et "Terminé ..." ne sont pas adjacentes / séquentielles. Merci @Thor!
PattMauler
Vous êtes le bienvenu. Cela devrait fonctionner efficacement avec une entrée de taille (presque) arbitraire car il ne stocke que l'ID et le temps de recherche est O (1).
Thor
Agréable. Une seule chose: comme je l'ai appris de @RobertL ( unix.stackexchange.com/a/243550/135943 ), vous n'avez pas besoin d'attribuer une valeur pour créer un élément de tableau. Donc, au lieu de I[$5] = 1, vous pouvez simplement utiliser I[$5]. (Vous ne vous souciez pas de la valeur, vous voulez simplement faire exister l'élément , et simplement le nommer accomplit cela.)
Wildcard
@Wildcard: Vous avez raison, mais après avoir examiné la question de l'OP et la sortie de type grep qu'il recherche, il est plus approprié de se souvenir de la ligne entière et de la restituer à la fin.
Thor
3
sed '$!N;/\n.*completed/d;P;D' <input

Cela supprimera de la sortie toutes les lignes d'entrée qui ne sont pas suivies d'une ligne correspondant à la chaîne terminée .

mikeserv
la source
2

Voici comment vous pouvez le faire avec GNU sed:

sed -r 'N; /([0-9]+)\n\w+\s+\1/d; P; D' infile
  • N lit une ligne de plus dans l'espace de motif.
  • La correspondance d'expression régulière vérifie si des identifiants identiques sont trouvés, si c'est le cas, l'espace de modèle est supprimé ( d) et le cycle est redémarré.
  • S'il ne correspond pas, imprimez la première ligne dans l'espace de motif ( P) et supprimez-la ( D).
Thor
la source
Je ne vois rien de étendu ici ... donc ce -rn'est pas nécessaire, non?
Louis Maddox
1
@lmmx: Il est nécessaire car sinon le groupe de capture doit être échappé, et il en va de même pour le +quantificateur.
Thor
Ah ok! Je l'ai modifié et on m'a dit que ce n'était pas nécessaire, merci pour la clarification
Louis Maddox
1

si votre installation prend en charge pcregrep, l'option multiligne (-M) est très pratique.

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

Activité de démarrage pour ID 33367

iruvar
la source