Найдите шаблон и напечатайте предыдущие строки, начиная с другого шаблона

Мне нужно grep для шаблона, и как только я нахожу его, мне нужно найти еще один шаблон, предшествующий этому, и напечатать все эти строки между ними.

Лучший пример:

1 a 2 a 3 a 4 a 5 a 6 b 7 c 8 d 9 xyz 10 xyz 11 a 12 a 

Grep для xyz а затем grep для первой предыдущей строки xyz и печати всех строк.

Вывод (первое предыдущее появление a , я не забочусь о других a в файле):

 5 a 6 b 7 c 8 d 9 xyz 10 xyz 

4 Solutions collect form web for “Найдите шаблон и напечатайте предыдущие строки, начиная с другого шаблона”

Вот решение в Perl:

 perl -nlE ' if (/a/) { @buffer = ($_) } elsif (/xyz/) { push @buffer,$_; say for @buffer } else { push @buffer,$_} ' your_file 

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

Он читает файл по очереди и выполняет одно из трех действий:

  1. Если текущая строка соответствует шаблону a , она назначает текущую строку массиву @buffer .
  2. Если текущая строка соответствует шаблону xyz , он подталкивает текущую строку в буфер и печатает содержимое буфера
  3. Если ни один из двух вышеперечисленных случаев не является истинным, он просто присоединяет текущую строку к массиву @buffer .

Таким образом, всякий раз, когда новая строка соответствует шаблону a , содержимое @buffer стирается и заменяется только текущей строкой. Это гарантирует, что вы найдете ближайший предшествующий xyz .

Вы должны, конечно, заменить регулярные выражения, которые я использовал с реальными регулярными выражениями, относящимися к вашему делу.

Я думаю, вы могли бы сделать что-то вроде

 grep -zPo '.*a(?s)(?(?!a).)*?xyz' file 

(с GNU grep, если ваша версия достаточно недавняя, чтобы поддерживать расширение PCRE) или

 pcregrep -Mo '.*a(?s)(?(?!a).)*?xyz' file 

Если вы хотите соответствовать второму экземпляру xyz в своем выходе, сделайте матч жадным, удалив финальный ? например grep -zPo '.*a(?s)(?(?!a).)*xyz' file .


Возможно, лучший тест – это многосимвольные шаблоны как для начала, так и для остановки; данный

 $ cat file 1 abc 2 abc 3 abc 4 abc 5 abc 6 bbc 7 cbc 8 dbc 9 xyz 10 xyz 11 abc 12 abc 

тогда

 $ grep -zPo '.*abc(?s)(?(?!abc).)*?xyz' file 5 abc 6 bbc 7 cbc 8 dbc 9 xyz 
 tac file | sed '/xyz/,/a/!d' | tac 

(если у вас нет tac , у вашей команды tail может быть команда -r чтобы сделать то же самое).

Если вам не нужны пустые строки на выходе, попробуйте:

 $ awk ' !NF { next } /a/ { flag = 1; last = $0; next } last && flag { print last; print; last = 0; next} /xyz/ { print; flag = 0; next} flag ' file 5 a 6 b 7 c 8 d 9 xyz 10 xyz 
  • Рекурсивно найти файлы, которые имеют процент общих линий
  • Как я могу улучшить вывод find и grep?
  • Найти, сочетание xargs и grep вызывает ошибку
  • Может кто-нибудь уточнить этот сценарий Bash
  • Получить `grep`, чтобы не выводить имя файла
  • Grep строка из того же файла в нескольких файлах .tar.gz
  • копировать строки, где символ встречается ровно столько раз
  • Проблема с журналом реального времени, проверяющим хвост трубопровода, grep и разрез
  • Греп игнорирует часть моего рисунка?
  • Справка Grep regex нужна
  • Обратный grepping
  • Как отображать числа только в конце переменной в bash?
  • Linux и Unix - лучшая ОС в мире.