Поиск блока текста с частями, которые могут быть необязательными

Поиск блока текста с частями, которые могут быть необязательными

У меня есть несколько записей, описывающихсобытиев очень большом файле журнала, скажемВойти. Я хотел бы сделать две вещи ссобытиеЗаписи в файле журнала:

  1. Подсчитайте количество появлений каждой такой записи. (Это не обязательное требование, но было бы неплохо иметь его.)
  2. Извлеките фактические записи в отдельный файл и изучите их позже.

Типичная запись события будет выглядеть следующим образом и будет иметь другие тексты между ними. Так, в примере ниже есть двасобытиезаписи, первая из которых содержит две DataChangeEntry полезные нагрузки, а вторая — одну DataChangeEntry полезную нагрузку.

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

    ]]

Обратите внимание, что количество ==== DataChangeEntryстрок в записи события может быть переменным. Оно также может полностью отсутствовать, что будет указывать на пустую полезную нагрузку событий и является условием ошибки, и я определенно хотел бы отловить этот случай.

Поскольку в этом случае вывод записи охватывает несколько строк, я не смогу добиться успеха, используя обычный ванильный grep. Поэтому я ищу совета у эксперта.

P.S.:

  1. Позвольте мне более четко сформулировать свое требование. Я хотел бы захватить весь блок текста, показанный выше, дословно и, по желанию, подсчитать количество обнаруженных экземпляров таких блоков. Возможность подсчета количества экземпляров хороша, но не является обязательным требованием.
  2. Если решение проблемы заключается в использовании awk, я бы хотел сохранить файл awk и использовать его повторно. Поэтому, пожалуйста, укажите шаги для выполнения скрипта. Я знаю regex и grep, но я не знаком с sed и/или awk.

решение1

Надеюсь, это сработает. События отправляются в eventsфайл. А сообщения отправляются в stdout.

Сохраните этот файл в 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
}

Вызвать его можно разными способами:

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

Пример вывода:

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

Вы можете проверить все события вместе в файле, который находится eventsв рабочем каталоге.

решение2

Очень простой подход был бы

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

Это создаст отдельный файл для каждой записи и выведет количество найденных записей на стандартный вывод.

Объяснение

  • NR— это текущий номер строки в awk.
  • RS="]]"устанавливает разделитель записей (то, что определяет "строку") на ]]. Это означает, что каждая запись будет рассматриваться как одна строка awk.
  • {print > NR".entry"}: это печатает текущую строку (запись) в файл с именем [LineNumber].entry. Таким образом, 1.entryбудет содержать 1-ю, 2.entryвторую и т. д.
  • END{print NR" entries"}: блок END выполняется после обработки всего входного файла. Таким образом, в этой точке NRбудет количество обработанных записей.

Вы можете сохранить это как псевдоним или превратить в скрипт, например, так:

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

Затем вы запускаете скрипт (предполагая, что он вызван foo.shи находится в вашем $PATH) с целевым файлом в качестве аргумента:

foo.sh file

Вы также можете изменить имена выходных файлов. Например, чтобы файлы назывались, [date].[entry number].[entry]используйте это:

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

Вышеизложенное предполагает, что ваш файл журнала состоит исключительно из записей "Событие". Если это не так, и у вас могут быть другие строки, и эти строки следует игнорировать, используйте это вместо этого:

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

Или, вкратце:

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 

Связанный контент