скрипт sed для печати n строк после последнего совпадения

Недавно в OpenSuse -скользящий выпуск Tumbleweed установил LTO на gcc9 для своих сборок.http://hubicka.blogspot.com/2019/05/gcc-9-link-time-and-inter-procedural.html

-1
29.04.2021, 20:58
6 ответов

Использование awk:

awk '/====/{ buf=""; c=0; found=1; next }
    ++c<=2 { buf=(buf==""?"":buf ORS) $0 }
END{ if(c>=2 && found)print buf }' infile

Вход:

====
1
2
3
4
====
11
22
33
====
111
222
333
444
====
1111
2222
3333

Выход:

1111
2222
3
28.07.2021, 11:36

Используя sedи предполагая, что вам нужны две строки после последнего совпаденияpattern(и дополнительно предполагая, что каждая строка, соответствующая pattern, отделена как минимум двумя строками от любой другой совпадающей строки):

$ cat file
a
b       pattern
c       the 1st
d       the 2nd
e       the 3rd
1
2
3       pattern
4       the first
5       the second
6       the third
7
$ sed -n -e '/pattern/ { n; N; h; }' -e '$ { g; /./p; }' file
4       the first
5       the second

Команда sedсчитывает следующую строку с nпри совпадении pattern.Строка после этого добавляется в буфер с Nи обе строки копируются в пространство хранения сh(поверх -с записью всего, что раньше хранилось там ).

Когда мы доходим до последней строки, мы получаем пространство хранения, которое теперь содержит две самые последние строки после строки, совпадающей с pattern, или пусто, если не совпадало pattern. Если буфер не пуст, он выводится.

Чтобы получить три строки после строки, соответствующей pattern, используйте n; N; N; h;вместо n; N; h;.

Получение трех строк после сопоставления строкpattern(теперь предполагается, что совпадающие строки разделены не менее чем тремя строками):

$ sed -n -e '/pattern/ { n; N; N; h; }' -e '$ { g; /./p; }' file
4       the first
5       the second
6       the third

Устранение необходимости в том, чтобы строки, соответствующие pattern, находились далеко друг от друга, нам нужно проверить, соответствует ли какая-либо из «строк после» patternпри их чтении, и если это так, перезапустить оттуда.

sed -n -e ':a' -e '/pattern/ { n; /pattern/ba; N; /pattern/ba; h; }' -e '$ { x; /./p; }' file
3
28.07.2021, 11:36

Вы можете использоватьed:

printf '%s\n' '?pattern?+1, ?pattern?+2 p' | ed -s file

Это отправляет одну команду на edна стандартный ввод; флаг -sзапрещает подсчет байта -в качестве вывода при чтении файла. Команда ломается следующим образом:

  • ...,... p--вывести строки в заданном (...,... )диапазоне адресов
  • ?pattern?+1--выполнить поиск patternв обратном направлении, затем добавить один
  • ?pattern?+2--выполнить поиск patternв обратном направлении, затем добавить два

Текущим значением по умолчанию является последняя строка файла, поэтому при поиске будет найдено последнее вхождение patternв файле. Затем смещения выбирают две следующие строки.

5
28.07.2021, 11:36

Используя GNU grepи tailи пример файла αғsнιη:

$ cat file
====
1
2
3
4
====
11
22
33
====
111
222
333
444
====
1111
2222
3333

$ grep  -A2 "====" file  | tail -n2
1111
2222

-A2указывает grepнапечатать соответствующую строку (, в данном случае мы ищем====)и две строки после нее. Затем tail -n2печатает только две последние строки.

Если ваш файл очень большой, вы можете ускорить его, читая с конца файла с помощью tacи обращая логику:

$ tac file | grep -m1 -B2 "====" | tac |tail -n2
1111
2222
5
28.07.2021, 11:36

Использование awk:

awk '{ arr[NR]=$0; if ($0 ~ /====/) line=NR}END{if (line) for(i=line+1;i<=line+2;i++) print arr[i]}' file

arr[NR] = $0создает массив, содержащий все записи файла.

Затем if ($0 ~ /====/) line=NR}находит последнюю запись файла, содержащую этот шаблон. Это выражение можно записать как if (/====/) line=NR.

И, наконец, цикл for выводит строки после последнего совпадения. Если требуются три строки, размер цикла можно изменить на 3 с помощью i<=line+3.

if (line)предотвратит печать первых двух строк файла, если шаблон не найден.

Но что, если шаблон найден в последней записи файла. Приведенное выше решение будет печатать пустые строки.

Следующее будет работать только в том случае, если в файле есть по крайней мере две записи после записи, содержащей этот шаблон.

awk '{ arr[NR]=$0; if ($0 ~ /====/) line=NR}END{if (line) for(i=line+1;i<=line+2;i++){ if (i < (NR -1)) print arr[i]}}' file

Следующее должно работать, если в файле есть одна или две записи после этого шаблона. Это ничего не даст, если шаблон будет найден в последней строке.

awk '{ arr[NR]=$0; if ($0 ~ /====/) line=NR}END{if (line) for(i=line+1;i<=line+2;i++){ if (i <= NR) print arr[i]}}' file

0
28.07.2021, 11:36

GNU sed в расширенном режиме регулярных выражений -EИзмените переменную оболочки на количество строк, которое вы хотите видеть.

n=2
sed -Ee '
  /\n/q
  /pattern/{
    :loop
      $d;N
    /(.*\n){'"$n"'}/!bloop
    x
  }
  $!d;x
  /\n.*\n/D
  s/.*\n//p;d
' file
  • После того, как линия шаблона найдена, настройте цикл для накопления линий в пространстве шаблона.
  • остановить, когда будет видна n --я строка после строки шаблона (без учета строки шаблона ).
  • сохранить эти n+1 строк в удержании и, если не достигнут eof, перезапустить поиск следующего возможного появления шаблона.
  • Наконец, в eof извлеките данные области хранения и удалите из нее первую строку (строки шаблона ).
0
28.07.2021, 11:36

Теги

Похожие вопросы