Как выбрать линии между двумя шаблонами маркеров, которые могут возникать несколько раз с 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 делать это повторно до конца файла?

8 90

8 ответов:

использовать 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 : если flag равно 1 строка печатается.

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

используя sed:

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

The -n опции не печатать по умолчанию.

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

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

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

удалить все строки, кроме тех, между строками, начиная abc и mno

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

гольфы два символа лучше, чем ppotong это{//!b};d

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

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

этой кажется, POSIX:

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

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

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

ответ Don_cristi от показать только текст между 2 шаблон?

firstmatch="abc"
secondmatch="cdf"
sed "/$firstmatch/,/$secondmatch/!d;//d" infile

что намного эффективнее, чем приложение AWK, см. здесь.

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

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

.awk:
BEGIN {
    record=0
}

/^abc$/ {
    record=1
}

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

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

использование: awk -f file.awk data...

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