Использование grep или другой команды для возврата номера строки многострочного шаблона - PullRequest
3 голосов
/ 16 апреля 2019

Я использовал команду less для просмотра очень большого текстового файла журнала (15 ГБ) и пытался найти многострочный шаблон, но после некоторого исследования команда less может искать только однострочный шаблон.

Есть ли способ использовать grep или другие команды для возврата числовой строки многострочного шаблона?

Формат журнала примерно такой же: сотни итераций:

Packet A
op_3b       : 001
ctrl_2b     : 01
ini_count   : 5

Packet F
op_3b       : 101
ctrl_2b     : 00
ini_count   : 4

Packet X
op_3b       : 010
ctrl_2b     : 11
ini_count   : 98

Packet CA
op_3b       : 100
ctrl_2b     : 01
ini_count   : 5

Packet LP
op_3b       : 001
ctrl_2b     : 00
ini_count   : 0

Packet ZZ
op_3b       : 111
ctrl_2b     : 01
ini_count   : 545

Packet QEA
op_3b       : 111
ctrl_2b     : 11
ini_count   : 0

И я пытаюсь получить grep или какую-либо другую команду, чтобы вернуть начало номера строки, когда встречаются эти три строки шаблона:

op_3b       : 001
ctrl_2b     : 00
ini_count   : 0

Ответы [ 4 ]

5 голосов
/ 16 апреля 2019

Предположим, что шаблон находится в файле pattern следующим образом:

$ cat pattern
op_3b       : 001
ctrl_2b     : 00
ini_count   : 0

Затем попробуйте:

$ awk '$0 ~ pat' RS=  pat="$(cat pattern)" logfile
Packet LP
op_3b       : 001
ctrl_2b     : 00
ini_count   : 0

Как это работает

  • RS=

    Устанавливает разделитель записей RS на пустую строку.Это говорит awk использовать пустую строку в качестве разделителя записей.

  • pat="$(cat pattern)"

    Это говорит awk о создании переменной awk pat, которая содержит содержимоефайл pattern.

    Если ваша оболочка - bash, то несколько более эффективной формой этой команды будет pat="$(<pattern)".(Не используйте это, если вы не уверены , что ваша оболочка bash.)

  • $0 ~ pat

    Это говорит awk о печати любогозапись, соответствующая шаблону.

    $0 - содержимое текущей записи.~ говорит awk сделать совпадение между текстом в $0 и регулярным выражением в pat.

    (Если бы содержимое pattern содержало какие-либо активные символы регулярного выражения, нам нужно было бы экранироватьих. Ваш текущий пример не имеет, так что это не проблема.)

Альтернативный стиль

Некоторые люди предпочитают другой стиль для определения переменных awk:

$ awk -v RS=  -v pat="$(cat pattern)" '$0 ~ pat' logfile
Packet LP
op_3b       : 001
ctrl_2b     : 00
ini_count   : 0

Это работает так же.

Отображение номеров строк

$ awk -F'\n' '$0 ~ pat{print "Line Number="n+1; print "Packet" $0} {n=n+NF-1}' RS='Packet'  pat="$(cat pattern)" logfile
Line Number=20
Packet LP
op_3b       : 001
ctrl_2b     : 00
ini_count   : 0
2 голосов
/ 16 апреля 2019

Вот моя скудная попытка:

awk -v RS="" -v FS="\n" -v op=001 -v ctrl=00 -v ini=0 '$2~op&&$3~ctrl&&$4~ini' data.txt
1 голос
/ 16 апреля 2019

На сегодняшний день лучшим подходом является John1024 с использованием awk, поскольку вы можете сделать это за один проход, если вы действительно хотите использовать решение grep, вы можете использовать:

$ grep -m 1 -zoP 'Packet\s*[^\s]*\s*(?=op_3b\s*:\s*001\s*ctrl_2b\s*:\s*00\sini_count\s*:\s*0)' file
Packet LP

Примечания:

  • -m 1 возвратит grep после первого совпадения, вы можете удалить его, если ваш шаблон появляется несколько раз.
  • -z допускает многострочные шаблоны, так как он позволяет символу ASCII NUL вместо обычного EOL
  • -o просто отображать совпадение результата как выходной, а не весь файл
  • -P для активации регулярного выражения Perl

Если вы хотите, чтобы номер строки:

grep -n -f <(grep -m 1 -zoP 'Packet\s*[^\s]*\s*(?=op_3b\s*:\s*001\s*ctrl_2b\s*:\s*00\sini_count\s*:\s*0)' file) file
21:Packet LP

Однако вам нужно сделать 2 прохода, поэтомудля файла 15 ГБ awk - лучший подход.

0 голосов
/ 16 апреля 2019

если ваши данные в файле 'd' попробуйте:

grep -nEA2 '^op_3b\s*:\s*001' d

изменить номер 001 выше, как ваш поиск ключа

...