Могут ли шаблоны awk соответствовать нескольким строкам?
У меня есть несколько сложных файлов журналов, которые мне нужны для написания некоторых инструментов для их обработки. Я играл с awk, но я не уверен, что awk - правильный инструмент для этого.
Мои файлы журнала - это распечатки протоколов протокола OSPF, которые содержат текстовый журнал различных протоколов pkts и их содержимого с их различными полями протокола, идентифицированными с их значениями. Я хочу обработать эти файлы и распечатать только определенные строки журнала, относящиеся к конкретным pkts. Каждый журнал pkt может состоять из различного количества строк для этой записи pkt.
awk, похоже, способен обрабатывать одну строку, которая соответствует шаблону. Я могу найти нужный pkt, но тогда мне нужно сопоставить шаблоны в строках, которые следуют, чтобы определить, является ли это pkt, который я хочу распечатать.
Еще один способ взглянуть на это - я хотел бы выделить несколько строк в файле журнала и распечатать те строки, которые являются деталями конкретного pkt на основе совпадений шаблонов на нескольких строках.
Поскольку awk кажется линейным, я не уверен, что это лучший инструмент для использования.
Если awk может это сделать, как это сделать? Если нет, какие-либо предложения по использованию какого-либо инструмента для этого?
Ответы
Ответ 1
Awk может легко обнаруживать многострочные комбинации шаблонов, но вам нужно создать так называемый конечный автомат , чтобы распознать последовательность.
Рассмотрим этот вход:
how
second half #1
now
first half
second half #2
brown
second half #3
cow
Как вы видели, легко распознать один шаблон. Теперь мы можем написать awk-программу, которая распознает вторую половину только тогда, когда ей непосредственно предшествует первая половина строки. (С более сложным конечным автоматом вы можете обнаружить произвольную последовательность шаблонов.)
/second half/ {
if(lastLine == "first half") {
print
}
}
{ lastLine = $0 }
Если вы запустите это, вы увидите:
second half #2
Теперь этот пример абсурдно прост и всего лишь конечный автомат. Интересное состояние длится только в течение срока действия оператора if, а предыдущее состояние неявно, в зависимости от значения lastLine. В более канонической машине состояния вы должны сохранять явную переменную состояния и переходить из состояния в состояние в зависимости как от существующего состояния, так и от текущего ввода. Но вам может не понадобиться такой механизм управления.
Ответ 2
Awk действительно основан на записи. По умолчанию он думает о строке как записи, но вы можете изменить ее с помощью переменной RS (разделителя записей).
Один из способов приблизиться к этому - сделать первый проход с помощью sed (вы можете сделать это с помощью awk, если хотите), чтобы отделить записи с другим символом, таким как форма-фид. Затем вы можете написать свой awk script, где он будет обрабатывать группу строк как одну запись.
Например, если это ваши данные:
animal 0
name: joe
type: dog
animal 1
name: bill
type: cat
animal 2
name: ed
type: cat
Чтобы отделить записи с формами:
$ cat data | sed $'s|^\(animal.*\)|\f\\1|'
Теперь мы возьмем это и передадим через awk. Вот пример условной печати записи:
$ cat data | sed $'s|^\(animal.*\)|\f\\1|' | awk '
BEGIN { RS="\f" }
/type: cat/ { print }'
выходы:
animal 1
name: bill
type: cat
animal 2
name: ed
type: cat
Изменить: в качестве бонуса здесь, как это сделать с awk-ward ruby (-014 означает использование формы-подачи (восьмеричный код 014) в качестве разделителя записей):
$ cat data | sed $'s|^\(animal.*\)|\f\\1|' |
ruby -014 -ne 'print if /type: cat/'
Ответ 3
awk может обрабатывать от начального шаблона до конечного шаблона
/start-pattern/,/end-pattern/ {
print
}
Я искал как соответствовать
* Implements hook_entity_info_alter().
*/
function file_test_entity_type_alter(&$entity_types) {
так создано
/\* Implements hook_/,/function / {
print
}
какой контент мне нужен. Более сложный пример - пропустить строки и удалить незаполненные части. Примечание awk - это инструмент записи (строка) и слово (разделенный пробелом).
# start,end pattern match using comma
/ \* Implements hook_(.*?)\./,/function (.\S*?)/ {
# skip PHP multi line comment end
$0 ~ / \*\// skip
# Only print 3rd word
if ($0 ~ /Implements/) {
hook=$3
# scrub of opening parenthesis and following.
sub(/\(.*$/, "", hook)
print hook
}
# Only print function name without parenthesis
if ($0 ~ /function/) {
name=$2
# scrub of opening parenthesis and following.
sub(/\(.*$/, "", name)
print name
print ""
}
}
Надеюсь, это тоже поможет.
Смотрите также ftp://ftp.gnu.org/old-gnu/Manuals/gawk-3.0.3/html_chapter/gawk_toc.html
Ответ 4
Я делаю такие вещи с журналами sendmail, время от времени.
Дано:
Jan 15 22:34:39 mail sm-mta[36383]: r0B8xkuT048547: to=<[email protected]>, delay=4+18:34:53, xdelay=00:00:00, mailer=esmtp, pri=21092363, relay=web3., dsn=4.0.0, stat=Deferred: Operation timed out with web3.
Jan 15 22:34:39 mail sm-mta[36383]: r0B8hpoV047895: to=<[email protected]>, delay=4+18:49:22, xdelay=00:00:00, mailer=esmtp, pri=21092556, relay=web3., dsn=4.0.0, stat=Deferred: Operation timed out with web3.
Jan 15 22:34:51 mail sm-mta[36719]: r0G3Youh036719: from=<[email protected]>, size=0, class=0, nrcpts=0, proto=ESMTP, daemon=IPv4, relay=[50.71.152.178]
Jan 15 22:35:04 mail sm-mta[36722]: r0G3Z2SF036722: lost input channel from [190.107.98.82] to IPv4 after rcpt
Jan 15 22:35:04 mail sm-mta[36722]: r0G3Z2SF036722: from=<[email protected]>, size=0, class=0, nrcpts=0, proto=SMTP, daemon=IPv4, relay=[190.107.98.82]
Jan 15 22:35:36 mail sm-mta[36728]: r0G3ZXiX036728: lost input channel from ABTS-TN-dynamic-237.104.174.122.airtelbroadband.in [122.174.104.237] (may be forged) to IPv4 after rcpt
Jan 15 22:35:36 mail sm-mta[36728]: r0G3ZXiX036728: from=<[email protected]>, size=0, class=0, nrcpts=0, proto=SMTP, daemon=IPv4, relay=ABTS-TN-dynamic-237.104.174.122.airtelbroadband.in [122.174.104.237] (may be forged)
Я использую script что-то вроде этого:
#!/usr/bin/awk -f
BEGIN {
search=ARGV[1]; # Grab the first command line option
delete ARGV[1]; # Delete it so it won't be considered a file
}
# First, store every line in an array keyed on the Queue ID.
# Obviously, this only works for smallish log segments, as it uses up memory.
{
line[$6]=sprintf("%s\n%s", line[$6], $0);
}
# Next, keep a record of Queue IDs with substrings that match our search string.
index($0, search) {
show[$6];
}
# Finally, once we've processed all input data, walk through our array of "found"
# Queue IDs, and print the corresponding records from the storage array.
END {
for(qid in show) {
print line[qid];
}
}
чтобы получить следующий вывод:
$ mqsearch airtel /var/log/maillog
Jan 15 22:35:36 mail sm-mta[36728]: r0G3ZXiX036728: lost input channel from ABTS-TN-dynamic-237.104.174.122.airtelbroadband.in [122.174.104.237] (may be forged) to IPv4 after rcpt
Jan 15 22:35:36 mail sm-mta[36728]: r0G3ZXiX036728: from=<[email protected]>, size=0, class=0, nrcpts=0, proto=SMTP, daemon=IPv4, relay=ABTS-TN-dynamic-237.104.174.122.airtelbroadband.in [122.174.104.237] (may be forged)
Идея здесь в том, что я печатаю все строки, которые соответствуют идентификатору очереди Sendmail строки, которую я хочу найти. Структура кода, конечно, является продуктом структуры файла журнала, поэтому вам нужно будет настроить свое решение для данных, которые вы пытаетесь проанализировать и извлечь.
Ответ 5
`pcregrep -M` works pretty well for this.
Из pcregrep (1):
-M, - multiline
Разрешить шаблонам соответствовать более одной строке. Когда этот параметр задан, шаблоны могут с пользой содержать литеральные символы новой строки и внутренние вхождения символов ^ и $. Результат для успешного совпадения может состоять из более чем одна строка, последним из которых является та, в которой матч закончился. Если согласованная строка заканчивается последовательностью новой строки, выход заканчивается на конец этой строки.
Когда эта опция установлена, библиотека PCRE вызывается в "многострочном" Режим. Существует ограничение на количество строк, которые могут быть сопоставлены, наложенным тем, что pcregrep буферизует входной файл при его сканировании Это. Однако pcregrep гарантирует, что не менее 8K символов или остальных документа (в зависимости от того, что короче) доступны для пересылки сопоставление и аналогичные предыдущие 8K символов (или все предыдущие символы, если менее 8K) гарантированно будут доступны для утверждений о взгляде. Этот параметр не работает, когда вход прочитайте строку за строкой (см. строку-буферизацию.)