
У меня есть несколько записей, описывающихсобытиев очень большом файле журнала, скажемВойти. Я хотел бы сделать две вещи ссобытиеЗаписи в файле журнала:
- Подсчитайте количество появлений каждой такой записи. (Это не обязательное требование, но было бы неплохо иметь его.)
- Извлеките фактические записи в отдельный файл и изучите их позже.
Типичная запись события будет выглядеть следующим образом и будет иметь другие тексты между ними. Так, в примере ниже есть двасобытиезаписи, первая из которых содержит две 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.:
- Позвольте мне более четко сформулировать свое требование. Я хотел бы захватить весь блок текста, показанный выше, дословно и, по желанию, подсчитать количество обнаруженных экземпляров таких блоков. Возможность подсчета количества экземпляров хороша, но не является обязательным требованием.
- Если решение проблемы заключается в использовании 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