Как выбрать линии между двумя шаблонами маркеров, которые могут возникать несколько раз с помощью awk/sed

Используя awk или sed, как я могу выбрать строки, которые происходят между двумя разными маркерными шаблонами? Может быть несколько разделов, помеченных этими шаблонами.

Например: Предположим, что файл содержит:

abc
def1
ghi1
jkl1
mno
abc
def2
ghi2
jkl2
mno
pqr
stu

И начальный шаблон abc, а конечный шаблон - mno Итак, мне нужен вывод как:

def1
ghi1
jkl1
def2
ghi2
jkl2

Я использую sed для соответствия шаблону один раз:

sed -e '1,/abc/d' -e '/mno/,$d' <FILE>

Есть ли способ в sed или awk сделать это несколько раз до конца файла?

Ответ 1

Используйте awk с флагом для запуска печати при необходимости:

$ awk '/abc/{flag=1;next}/mno/{flag=0}flag' file
def1
ghi1
jkl1
def2
ghi2
jkl2

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

  • /abc/ соответствует линиям, имеющим этот текст, а также /mno/.
  • /abc/{flag=1;next} устанавливает flag, когда текст abc найден. Затем он пропускает строку.
  • /mno/{flag=0} выводит flag при появлении текста mno.
  • Финал flag - это шаблон с действием по умолчанию, который равен print $0: если flag равно 1, строка печатается.

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

Ответ 2

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

sed -n -e '/^abc$/,/^mno$/{ /^abc$/d; /^mno$/d; p; }'

Опция -n означает, что по умолчанию печать не выполняется.

Образец ищет строки, содержащие только abc, только mno, а затем выполняет действия в { ... }. Первое действие удаляет строку abc; вторая строка mno; и p печатает оставшиеся строки. Вы можете расслаблять регулярные выражения по мере необходимости. Любые строки вне диапазона abc.. mno просто не печатаются.

Ответ 3

Это может сработать для вас (GNU sed):

sed '/^abc$/,/^mno$/{//!b};d' file

Удалите все строки, кроме строк, начинающихся с abc и mno

Ответ 4

sed '/^abc$/,/^mno$/!d;//d' file

Гольфы два персонажа лучше, чем ppotong - х {//!b};d

Пустые косые черты // означают: "повторное использование последнего регулярного выражения". и команда делает то же самое, что и более понятное:

sed '/^abc$/,/^mno$/!d;/^abc$/d;/^mno$/d' file

Кажется, это POSIX:

Если RE пусто (т.е. Не указывается шаблон), sed должен вести себя так, как если бы последний RE использовался в последней применяемой команде (либо в качестве адреса, либо как часть замены).

Ответ 5

Из предыдущих ссылок ответа тот, который сделал это для меня, выполнив ksh на Solaris, был следующим:

sed '1,/firstmatch/d;/secondmatch/,$d'

Ответ 7

что-то вроде этого работает для меня:

file.awk:

BEGIN {
    record=0
}

/^abc$/ {
    record=1
}

/^mno$/ {
    record=0;
    print "s="s;
    s=""
}

!/^abc|mno$/ {
    if (record==1) {
        s = s"\n"$0
    }   
}

используя: awk -f file.awk data...

edit: решение O_o fedorqui лучше/красивее моего.

Ответ 8

perl -lne 'print if((/abc/../mno/) && !(/abc/||/mno/))' your_file