
Я пытаюсь напечатать только <N>
строку th перед шаблоном поиска. grep -B<N>
печатает все <N>
строки перед шаблоном поиска. Я видел код awkздеськоторый может напечатать только <N>
строку после шаблона поиска.
awk 'c&&!--c;/pattern/{c=N}' file
Как изменить это так, чтобы печатать только <N>
строку th перед каждой строкой, которая соответствует pattern
? Например, вот мой входной файл
...
...
0.50007496 0.42473932 0.01527831
0.99997456 0.97033575 0.44364198
Direct configuration= 1
0.16929051 0.16544726 0.16608723
0.16984300 0.16855274 0.50171112
...
...
0.50089841 0.42608090 0.01499159
0.99982054 0.97154975 0.44403547
Direct configuration= 2
0.16931296 0.16553376 0.16600890
0.16999941 0.16847055 0.50170694
...
Мне нужна команда, которая может вернуть мне 2nd line
предыдущую строку поиска Direct configuration
. Я пытаюсь запустить это вSUSE-Linux
решение1
Необходимо использовать буфер строк.
Попробуйте это:
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-й строке перед шаблоном для печати.
Задайте pattern
значение регулярного выражения для поиска.
buffer
массив N
элементов. Используется для хранения строк. Каждый раз, когда шаблон найден, N
печатается строка th перед шаблоном.
решение2
Этот код не работает для предыдущих строк. Чтобы получить строки до совпавшего шаблона, вам нужно как-то сохранить уже обработанные строки. Поскольку 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
Объяснение
perl -ne
: прочитать входной файл построчно и применить заданный скрипт-e
к каждой строке.push @lines,$_
: добавить текущую строку ($_
) в массив@lines
.print $lines[0] if /PAT/
: вывести первый элемент массива@lines
($lines[0]
), если текущая строка соответствует желаемому шаблону.shift(@lines) if $.>LIM;
:$.
— это номер текущей строки. Если он больше лимита, удалить первое значение из массива@lines
. Результатом будет то, что@lines
всегда будут последниеLIM
строки.
решение3
tac file | awk 'c&&!--c;/pattern/{c=N}' | tac
Но здесь есть тот же пробел, что и в случае использования «forward», когда есть несколько совпадений в пределах N строк друг от друга.
И это не будет работать так хорошо, если входные данные передаются из работающего процесса, но это самый простой способ, когда входной файл завершен и не растет.
решение4
Альтернативный способ с sed
.
ДляН=1:
sed '$!N; /.*\n.*pattern/P; D' FILE
ДляН=2
sed '1N; $!N; /.*\n.*\n.*pattern/P; D' FILE
ДляН=2случае, 1-я строка это будет читаться следующимН-1строки в пространстве шаблона, затем начать N;P;D
цикл — прочитать еще одну строку и, если последняя строка в пространстве шаблона совпадает, вывести первую строку в пространстве шаблона, затем удалить ее, начиная новый цикл.
Недостатком является то, что его необходимо модифицировать для разных значенийН:
ДляН=3:
sed '1{N;N}; $!N; /.*\n.*\n.*\n.*pattern/P; D' FILE
ДляН=4:
sed '1{N;N;N}; $!N; /.*\n.*\n.*\n.*\n.*pattern/P; D' FILE
поэтому он быстро становится громоздким, хотя для больших значенийНвы можете подготовить файл сценария и передать его sed
.