Suchen nach einem Textblock mit Teilen, die optional sein können

Suchen nach einem Textblock mit Teilen, die optional sein können

Ich habe mehrere Einträge, die eineEreignisin einer sehr großen Protokolldatei, sagen wirEin HolzklotzIch möchte zwei Dinge tun mit demEreignisEinträge in der Logdatei:

  1. Zählen Sie die Anzahl der Vorkommen jedes solchen Eintrags. (Dies ist keine zwingende Voraussetzung, wäre aber wünschenswert.)
  2. Extrahieren Sie die eigentlichen Einträge in eine separate Datei und studieren Sie sie später.

Ein typischer Ereigniseintrag würde wie folgt aussehen und zwischen den Einträgen weitere Texte enthalten. Im folgenden Beispiel gibt es also zweiEreignisEinträge, wobei der erste zwei DataChangeEntry Nutzlasten und der zweite eine DataChangeEntry Nutzlast enthält.

    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,  ]

    ]]

Bitte beachten Sie, dass die Anzahl der ==== DataChangeEntryZeilen in einem Ereigniseintrag variabel sein kann. Sie kann auch vollständig fehlen, was auf eine leere Ereignisnutzlast hinweist und einen Fehlerzustand darstellt. Auch diesen Fall möchte ich unbedingt abfangen.

Da sich in diesem Fall die Ausgabe von entry über mehrere Zeilen erstreckt, komme ich mit einfachem Vanilla-Grep nicht weit. Ich suche daher Expertenrat.

PS:

  1. Lassen Sie mich meine Anforderung genauer erläutern. Ich möchte den gesamten oben gezeigten Textblock wörtlich erfassen und optional die Anzahl der gefundenen Instanzen solcher Blöcke zählen. Die Option zum Zählen der Anzahl der Instanzen ist gut, aber keine zwingende Voraussetzung.
  2. Wenn die Lösung des Problems die Verwendung von awk ist, möchte ich die awk-Datei speichern und erneut verwenden. Bitte erwähnen Sie daher auch die Schritte zur Ausführung des Skripts. Ich kenne Regex und grep, aber ich bin nicht mit sed und/oder awk vertraut.

Antwort1

Ich hoffe, das würde es tun. Ereignisse werden in eventseine Datei geschrieben. Und Nachrichten werden an die Standardausgabe gesendet.

Speichern Sie diese Datei beispielsweise in myprogram.awk:

#!/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
}

Sie können es auf verschiedene Arten aufrufen:

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

Beispielausgabe:

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

Sie können alle Ereignisse zusammen in der Datei eventsim Arbeitsverzeichnis überprüfen.

Antwort2

Ein sehr einfacher Ansatz wäre

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

Dadurch wird für jeden Eintrag eine separate Datei erstellt und die Anzahl der gefundenen Einträge in der Standardausgabe gedruckt.

Erläuterung

  • NRist die aktuelle Zeilennummer in awk.
  • RS="]]"setzt den Datensatztrenner (was eine „Zeile“ definiert) auf ]]. Das bedeutet, dass jeder Eintrag von als einzelne Zeile behandelt wird awk.
  • {print > NR".entry"}: Dadurch wird die aktuelle Zeile (Eintrag) in eine Datei mit dem Namen gedruckt [LineNumber].entry. 1.entrySie enthält also die 1., 2.entrydie 2. usw.
  • END{print NR" entries"}: Der END-Block wird ausgeführt, nachdem die gesamte Eingabedatei verarbeitet wurde. Daher NRwird an diesem Punkt die Anzahl der verarbeiteten Einträge angezeigt.

Sie können dies als Alias ​​speichern oder wie folgt in ein Skript umwandeln:

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

Anschließend führen Sie das Skript (vorausgesetzt, es wird aufgerufen foo.shund befindet sich in Ihrem $PATH) mit der Zieldatei als Argument aus:

foo.sh file

Sie können auch die Namen der Ausgabedateien anpassen. Um die Dateien beispielsweise [date].[entry number].[entry]folgendermaßen zu benennen:

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

Das Obige setzt voraus, dass Ihre Protokolldatei ausschließlich aus „Ereignis“-Einträgen besteht. Wenn das nicht der Fall ist und Sie andere Zeilen haben können und diese Zeilen ignoriert werden sollen, verwenden Sie stattdessen Folgendes:

 #!/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 

Oder als Einzeiler:

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 

verwandte Informationen