Recherche d'un bloc de texte avec des parties qui peuvent être facultatives

8

J'ai plusieurs entrées qui décrivent un événement dans un très gros fichier journal, par exemple A.log . Je voudrais faire deux choses avec les entrées d' événement dans le fichier journal:

  1. Comptez le nombre d'occurrences de chacune de ces entrées (ce n'est pas une exigence obligatoire mais ce serait bien d'avoir).
  2. Extrayez les entrées réelles dans un fichier séparé et étudiez-les ultérieurement.

Une entrée d'événement typique ressemblerait à ce qui suit et aura d'autres textes entre eux. Ainsi, dans l'exemple ci-dessous, il y a deux entrées d' événement , la première contenant deux DataChangeEntry charges utiles et la seconde contenant une DataChangeEntry charge utile.

    Data control raising event :DataControl@263c015d[[
    #### DataChangeEvent #### on [DataControl name=PatternMatch_LegendTimeAxis, binding=.dynamicRegion1.                         beam_project_PatternMatch_dashboard_LegendTimeAxis_taskflow_LegendTimeAxis_beamDashboardLegendTimeAxisPageDef_beam_project_PatternMatch_dashboard_LegendTimeAxis_taskflow_LegendTimeAxis_beamDashboardLegendTimeAxis_xml_ps_taskflowid.dynamicRegion58.                                                                                                                         beam_project_PatternMatch_view_LegendTimeAxis_taskflow_LegendTimeAxis_beamVizLegendTimeAxisPageDef_beam_project_PatternMatch_view_LegendTimeAxis_taskflow_LegendTimeAxis_beamVizLegendTimeAxis_xml_ps_taskflowid.QueryIterator]
    Filter/Collection Id : 0
    Collection Level     : 0
    Sequence Id             : 616
    ViewSetId            : PatternMatch.LegendTimeAxis_V1_0_SN49
    ==== DataChangeEntry (#1)
    ChangeType           : UPDATE
    KeyPath              : [2014-06-26 06:15:00.0, 0]
    AttributeNames       : [DATAOBJECT_CREATED, COUNTX, QueryName]
    AttributeValues      : [2014-06-26 06:15:00.0, 11, StrAvgCallWaitTimeGreaterThanThreshold]
    AttributeTypes       : [java.sql.Timestamp, java.lang.Integer, java.lang.String,  ]
    ==== DataChangeEntry (#2)
    ChangeType           : UPDATE
    KeyPath              : [2014-06-26 06:15:00.0, 0]
    AttributeNames       : [DATAOBJECT_CREATED, COUNTX, QueryName]
    AttributeValues      : [2014-06-26 06:15:00.0, 9, AverageCallWaitingTimeGreateThanThreshold]
    AttributeTypes       : [java.sql.Timestamp, java.lang.Integer, java.lang.String,  ]

    ]]

someother non useful text
spanning multiple lines 

 Data control raising event :DataControl@263c015d[[
    #### DataChangeEvent #### on [DataControl name=PatternMatch_LegendTimeAxis, binding=.dynamicRegion1.                         beam_project_PatternMatch_dashboard_LegendTimeAxis_taskflow_LegendTimeAxis_beamDashboardLegendTimeAxisPageDef_beam_project_PatternMatch_dashboard_LegendTimeAxis_taskflow_LegendTimeAxis_beamDashboardLegendTimeAxis_xml_ps_taskflowid.dynamicRegion58.                                                                                                                         beam_project_PatternMatch_view_LegendTimeAxis_taskflow_LegendTimeAxis_beamVizLegendTimeAxisPageDef_beam_project_PatternMatch_view_LegendTimeAxis_taskflow_LegendTimeAxis_beamVizLegendTimeAxis_xml_ps_taskflowid.QueryIterator]
    Filter/Collection Id : 0
    Collection Level     : 0
    Sequence Id             : 616
    ViewSetId            : PatternMatch.LegendTimeAxis_V1_0_SN49
    ==== DataChangeEntry (#1)
    ChangeType           : UPDATE
    KeyPath              : [2014-06-26 06:15:00.0, 0]
    AttributeNames       : [DATAOBJECT_CREATED, COUNTX, QueryName]
    AttributeValues      : [2014-06-26 06:15:00.0, 11, StrAvgCallWaitTimeGreaterThanThreshold]
    AttributeTypes       : [java.sql.Timestamp, java.lang.Integer, java.lang.String,  ]

    ]]

Veuillez noter que le nombre de ==== DataChangeEntrylignes dans une entrée d'événement peut être variable. Il peut également être complètement absent, ce qui indiquerait une charge utile d'événements vide et constitue une condition d'erreur et aimerait certainement intercepter ce cas également.

Étant donné que dans ce cas, la sortie d'entrée s'étend sur plusieurs lignes, je ne vais pas loin en utilisant grep vanilla simple. Je recherche donc des conseils d'experts.

PS:

  1. Permettez-moi d'être plus explicite sur mon exigence. Je voudrais capturer l'intégralité du bloc de texte montré ci-dessus textuellement et éventuellement compter le nombre d'instances de ces blocs rencontrées. L'option de compter le nombre d'instances est bonne, mais n'est pas obligatoire.
  2. Si la solution au problème utilise awk, je voudrais enregistrer le fichier awk et le réutiliser. Veuillez donc également mentionner les étapes pour exécuter le script. Je connais regex et grep mais je ne connais pas sed et / ou awk.
Geek
la source
Commencent-ils toujours par Data control raising event?
LatinSuD
@LatinSuD oui, il commence toujours par cette chaîne.
Geek
Je pense que c'est un travail pour awk, en utilisant une ou plusieurs variables "machine d'état", mais vous devriez ajouter plus d'informations afin d'obtenir de l'aide, comme les jetons exacts recherchés et ce que vous attendez du résultat final.
Didi Kohen
@DavidKohen Une entrée d' événement commence par le jeton "Événement déclencheur de contrôle de données" et se termine par "]]" sur une nouvelle ligne. Je voudrais découvrir chacune de ces instances d' événements .
Geek
Trouvez quoi à leur sujet? Comptez leur montant? Les imprimer tous? Veuillez modifier votre question et ajouter un échantillon de sortie attendue (avec différents échantillons d'entrée de préférence).
Didi Kohen

Réponses:

4

J'espère que cela le fera. Les événements vont dans le eventsfichier. Et les messages vont à stdout.

Enregistrez ce fichier dans myprogram.awk (par exemple):

#!/usr/bin/awk -f

BEGIN {
   s=0;  ### state. Active when parsing inside an event
   nevent=0;  ### Current event number
   printf "" > "events"
}

# Start of event
/^ *Data control raising event/ {
   s=1;
   dentries=0;
   print "*** Event number: " nevent >> "events"
   nevent++
}

# Standard event line
s==1 {
   print >> "events"
}

# DataChangeEntry line
/^ *==== DataChangeEntry/ {
   dentries ++
}

# End of event
s==1 && /^ *\]\]/ {
   s=0;
   print "" >> "events"
   if(dentries==0){
      print "Warning: Event " nevent " has no Data Entries"
   }
}

END {
   print "Total event count: " nevent
}

Vous pouvez l'invoquer de différentes manières:

  • myprogram.awk inputfile.txt
  • awk -f myprogram.awk inputfile.txt

Exemple de sortie:

Warning: Event 3 has no Data Entries
Total event count: 3

Vous pouvez vérifier tous les événements ensemble dans le fichier appelé eventsdans le répertoire de travail.

LatinSuD
la source
Vous devez incrémenter le compteur d'événements séparément de l'en-tête de l'événement (ou avoir l'opérateur avant), cela entraîne l'affichage de nombres différents dans l'en-tête et le pied de page et est moins lisible.
Didi Kohen du
@LatinSuD Je ne connais pas awk. Donc, si vous pouvez ajouter la partie que je dois faire pour exécuter le programme ci-dessus, ce sera très utile. Pour moi, le fichier d'entrée est A.log .
Geek
Pour utiliser ce script, remplacez simplement le fichier inputfile.txt par votre nom de fichier, ou mieux, supprimez le chat et le tuyau et placez votre nom de fichier après le guillemet simple de fermeture.
Didi Kohen
@DavidKohen Je voudrais enregistrer ce script. Donc, si j'enregistre cela comme dire findEvents.awk. Puis-je l'exécuter comme ceci awk -f findEvents.awk A.log:?
Geek
Vous pouvez, mais vous ne devez enregistrer que la partie entre guillemets simples dans ce fichier.
Didi Kohen
2

Une approche très simple serait

awk '{print > NR".entry"}END{print NR" entries"}' RS="]]" file 

Cela créera un fichier séparé pour chaque entrée et imprimera le nombre d'entrées trouvées sur la sortie standard.

Explication

  • NRest le numéro de ligne actuel awk.
  • RS="]]"définit le séparateur d'enregistrement (ce qui définit une "ligne") sur ]]. Cela signifie que chaque entrée sera traitée comme une seule ligne par awk.
  • {print > NR".entry"}: ceci imprime la ligne courante (entrée) dans un fichier appelé [LineNumber].entry. Donc, 1.entrycontiendra le 1er, 2.entryle second et ainsi de suite.
  • END{print NR" entries"}: le bloc END est exécuté après que tout le fichier d'entrée a été traité. Par conséquent, à ce stade NRsera le nombre d'entrées traitées.

Vous pouvez l'enregistrer en tant qu'alias ou en faire un script comme ceci:

#!/usr/bin/env bash
awk '{print > NR".entry"}END{print NR" entries"}' RS="]]" "$1"

Vous devez ensuite exécuter le script (en supposant qu'il est appelé foo.shet se trouve dans votre $ PATH) avec le fichier cible comme argument:

foo.sh file

Vous pouvez également modifier les noms des fichiers de sortie. Par exemple, pour que les fichiers soient appelés, [date].[entry number].[entry]utilisez plutôt ceci:

#!/usr/bin/env bash
date=$(date +%Y%m%d)
awk '{print > d"."NR".entry"}END{print NR" entries"}' RS="]]" d="$date" "$1"

Ce qui précède suppose que votre fichier journal se compose exclusivement d'entrées "Événement". Si ce n'est pas le cas et que vous pouvez avoir d'autres lignes et que ces lignes doivent être ignorées, utilisez plutôt ceci:

 #!/usr/bin/env bash
date=$(date +%Y%m%d)
awk '{
        if(/\[\[/){a=1; c++;}
        if(/\]\]/){a=0; print > d"."c".entry"}
        if(a==1){print >> d"."c".entry"}
}' d="$date" file 

Ou, en une ligne:

awk '{if(/\[\[/){a=1; c++;}if(/\]\]/){a=0; print > d"."c".entry"}if(a==1){print >> d"."c".entry"}}' d=$(date +%Y%m%d) file 
terdon
la source