У меня есть огромный файл журнала, и я хочу проанализировать первое вхождение шаблона, а затем найти другой шаблон сразу после этого.
Например:
123
XXY
214
ABC
182
558
ABC
856
ABC
В моем примере я хотел бы найти, 182
а затем найти следующее вхождениеABC
Первое появление простое:
grep -n -m1 "182" /var/log/file
Это выводит:
5:182
Как мне найти следующее вхождение ABC?
Моя идея заключалась в том, чтобы сказать, grep
чтобы пропустить первые n
строки (в приведенном выше примере n=5
), на основе номера строки 182. Но как мне это сделать?
grep
которое используется? Я не думаю, что это можно сделать,grep
но было бы легко сawk
илиsed
(самостоятельно или в сочетании сgrep
).grep
не требуется. Я еще не очень знаком сsed
илиawk
. Если у вас есть хорошее решение, дайте мне услышать это! :) @don_crissti должна быть напечатана только первая строка. Я не забочусь о других случаях.Ответы:
С помощью
sed
вы можете использовать диапазон иq
вводить ввод при одном завершении:Аналогично с GNU
grep
вы можете разделить ввод между двумяgrep
s:... который печатает ...
... чтобы показать, что первый
grep
обнаружил, что-F
литерал с ixed-строкой,-x
вся строка 182 соответствует 5 строкам от начала его чтения, а вторая нашла аналогично набранный ABC, совпадающий с 2 строками с начала его чтения - или 2 строками после первогоgrep
прекращения чтения в строке 5.От
man grep
:Я использовал здесь документ для воспроизводимой демонстрации, но вы, вероятно, должны сделать:
Он также будет работать с другими конструкциями составных команд оболочки, такими как:
источник
grep
вместо;
... no-gogrep
разделяют эти два, является фактически конвейером для них. Что-то еще: я пытался без печати линии маркера, ноsed '//,/^ABC$/!d;/^ABC$/!d;q'
выдает странную ошибку. Что делает//
?sed
вещь - просто написал это очень быстро.sed
все работает - вы просто не указали. Вsed
последнем вы можете обратиться к последнему/address/
с пустым//
адресом. Так/^182$/command;//,/next_address/
просто/^182$/command;/^182$/,/next_address/
. Вероятно, вашей ошибкой не было предыдущего регулярного выражения, если вы использовали GNUsed
. Между прочим, с помощью функции pipe lseek можно манипулировать через косвенные/dev/fd/[num]
ссылки через ссылки в системах Linux - но если вы не очень осторожны в том, чтобы правильно обрабатывать буферы (например, с помощьюdd
) , это обычно проигрышная битва.Используйте
grep
с Perl-совместимыми регулярными выражениями (pcregrep
):Опция
-M
позволяет шаблону соответствовать более чем одной строке и\K
не включает сопоставленный шаблон (до этой точки) в вывод. Вы можете удалить,\K
если вы хотите получить весь регион в результате.источник
источник
awk '/^182$/{z=1;next} z&&/^ABC$/{print NR":"$0;exit}' file
- или вы можете написать хотя бы один явныйgetline()
цикл, который обычно неуклюже, или быть умным (?), используя диапазон почти такой же, как в perl @ JRFerguson:awk '!x&&/^182$/,/^ABC$/ {x=NR":"$0} END{print x}
Вариант Perl, который вы можете использовать:
... который печатает строки в соответствующем диапазоне.
Если файл содержит более одного совпадающего диапазона, вы можете ограничить вывод только первым диапазоном, изменив
/
разделитель на?
источник
Придерживаясь только
grep
и добавивtail
&cut
, вы могли бы ...grep для номера строки первого совпадения
182
:Используйте это для grep для всех
ABC
's только после первой соответствующей строки выше, используяtail
' s-n +K
для вывода после K '-ой строки. Все вместе:Или добавьте еще
-m 1
раз, чтобы найти только первое соответствиеABC
Ссылки:
man
страницы/programming/6958841/use-grep-to-report-back-only-line-numbers
источник
Другой вариант такой:
Флаг -A после матча набирает n строк, и 99999 просто для того, чтобы мы ничего не пропустили. Большие файлы должны иметь больше строк (проверьте с помощью "wc -l").
источник
Оператор диапазона
,
можно использовать здесь:Оператор диапазона
..
в тандеме с оператором «только один раз совпадения»m??
можно использовать здесь вPerl
источник