Печатать только N-ю строку перед каждой строкой, соответствующей шаблону

Вы также можете сделать это без print f :

awk 'BEGIN{ORS=""} {for(k=NF;k>0;--k) {print $k; if (k==1) print "\n"; else print " "}} ' file
5
16.05.2016, 20:41
4 ответа

Необходимо использовать буфер строк.

Попробуйте следующее:

awk -v N=4 -v pattern="example.*pattern" '{i=(1+(i%N));if (buffer[i]&& $0 ~ pattern) print buffer[i]; buffer[i]=$0;}' file

Установите значение N на N-ю строку перед шаблоном для печати.

Установить значение шаблона для регулярного выражения для поиска.

buffer - это массив из N элементов. Он используется для хранения строк. Каждый раз при нахождении шаблона печатается N -я строка перед шаблоном.

11
27.01.2020, 20:31

Этот код не работает для предыдущих строк. Чтобы линии были перед совпадающим шаблоном, нужно как-то сохранить уже обработанные строки. Поскольку awk имеет только ассоциативные массивы, я не могу придумать столь же простой способ сделать то, что вы хотите, в awk , поэтому вот решение на perl:

perl -ne 'push @lines,$_; print $lines[0] if /PAT/; shift(@lines) if $.>LIM;' file 

Изменить PAT для шаблона, который вы хотите сопоставить, и LIM для количества строк. Например, чтобы печатать 5-ю строку перед каждым появлением foo , вы должны выполнить:

perl -ne 'push @lines,$_; print $lines[0] if /foo/; shift(@lines) if $.>5;' file 

Explanation

  • perl -ne : прочитать входной файл построчно и применить данный сценарий по -e в каждую строку.
  • push @lines, $ _ : добавить текущую строку ( $ _ ) в массив @lines .
  • print $ lines [0] if / PAT / : распечатать первый элемент в массиве @lines ( $ lines [0] ), если текущая строка соответствует желаемый узор.
  • shift (@lines), если $.> LIM; : $. - текущий номер строки. Если это больше предела, удалите 1-е значение из массива @lines . В результате @lines всегда будут иметь последние LIM строк.
8
27.01.2020, 20:31
tac file | awk 'c&&!--c;/pattern/{c=N}' | tac

Но здесь есть то же упущение, что и в случае использования «вперед», когда есть несколько совпадений в пределах N строк друг от друга.

И это не будет работать так хорошо, если входные данные будут переданы из запущенного процесса, но это самый простой способ, когда входной файл завершен и не увеличивается.

4
27.01.2020, 20:31

Альтернативный способ с sed .

Для N = 1 :

sed '$!N; /.*\n.*pattern/P; D' FILE

Для N = 2

sed '1N; $!N; /.*\n.*\n.*pattern/P; D' FILE

Для случая N = 2 в первой строке будет указано следующее ] N-1 строк в пространстве шаблонов, затем запускает цикл N; P; D - считывает еще одну строку и, если последняя строка в пространстве шаблонов совпадает, печатает первую строку в шаблоне пробел, затем удалите его, начав новый цикл.

Обратной стороной является то, что его необходимо изменить для разных значений N :

Для N = 3 :

sed '1{N;N}; $!N; /.*\n.*\n.*\n.*pattern/P; D' FILE

Для N = 4 ]:

sed '1{N;N;N}; $!N; /.*\n.*\n.*\n.*\n.*pattern/P; D' FILE

, поэтому он быстро становится громоздким, хотя для больших значений N вы можете подготовить файл сценария и передать его в sed .

4
27.01.2020, 20:31

Теги

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