Buscando um bloco de texto com partes que podem ser opcionais

Buscando um bloco de texto com partes que podem ser opcionais

Tenho várias entradas que descrevem umeventoem um arquivo de log muito grande, digamosUm registo. Eu gostaria de fazer duas coisas com oeventoentradas no arquivo de log:

  1. Conte o número de ocorrências de cada entrada. (Este não é um requisito obrigatório, mas seria bom ter.)
  2. Extraia as entradas reais em um arquivo separado e estude-as mais tarde.

Uma entrada de evento típica teria a seguinte aparência e teria outros textos entre elas. Portanto, no exemplo abaixo, existem doiseventoentradas, a primeira contendo duas DataChangeEntry cargas úteis e a segunda contendo uma DataChangeEntry carga útil.

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

    ]]

Observe que o número de ==== DataChangeEntrylinhas em uma entrada de evento pode ser variável. Também pode estar completamente ausente, o que indicaria carga útil de eventos vazia e é uma condição de erro e definitivamente gostaria de capturar esse caso também.

Como neste caso a saída da entrada se estende por várias linhas, não estou indo muito longe usando o grep simples. Portanto, estou procurando aconselhamento especializado.

PS:

  1. Deixe-me ser mais explícito sobre minha exigência. Gostaria de capturar todo o bloco de texto mostrado acima literalmente e, opcionalmente, contar o número de instâncias de tais blocos encontradas. A opção de contar o número de instâncias é boa, mas não é um requisito obrigatório.
  2. Se a solução para o problema for usar o awk, gostaria de salvar o arquivo awk e reutilizá-lo. Portanto, mencione também as etapas para executar o script. Conheço regex e grep, mas não estou familiarizado com sed e/ou awk.

Responder1

Isso resolveria, espero. Os eventos vão para eventsarquivo. E as mensagens vão para stdout.

Salve este arquivo em myprogram.awk (por exemplo):

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

Você pode invocá-lo de diferentes maneiras:

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

Exemplo de saída:

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

Você pode verificar todos os eventos juntos no arquivo chamado eventsno diretório de trabalho.

Responder2

Uma abordagem muito simples seria

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

Isso criará um arquivo separado para cada entrada e imprimirá o número de entradas encontradas na saída padrão.

Explicação

  • NRé o número da linha atual em awk.
  • RS="]]"define o separador de registros (o que define uma "linha") como ]]. Isso significa que cada entrada será tratada como uma única linha por awk.
  • {print > NR".entry"}: imprime a linha atual (entrada) em um arquivo chamado [LineNumber].entry. Então, 1.entryconterá o 1º, 2.entryo segundo e assim por diante.
  • END{print NR" entries"}: o bloco END é executado após todo o arquivo de entrada ter sido processado. Portanto, nesse ponto NRserá o número de entradas processadas.

Você pode salvar isso como um alias ou transformá-lo em um script como este:

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

Você então executaria o script (supondo que ele seja chamado foo.she esteja em seu $PATH) com o arquivo de destino como argumento:

foo.sh file

Você também pode ajustar os nomes dos arquivos de saída. Por exemplo, para que os arquivos sejam chamados, [date].[entry number].[entry]use isto:

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

O texto acima pressupõe que seu arquivo de log consiste exclusivamente em entradas de "Eventos". Se esse não for o caso, e você puder ter outras linhas, e essas linhas devem ser ignoradas, use isto:

 #!/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, como uma linha:

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 

informação relacionada