it-roy-ru.com

Как выбрать линию между двумя шаблонами маркеров.

Используя 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 сделать это несколько раз до конца файла? 

103
dvai

Используйте 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, строка печатается.

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

161
fedorqui

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

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

Параметр -n означает, что по умолчанию не печатать.

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

38
Jonathan Leffler

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

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

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

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

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

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

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

Это кажется, POSIX :

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

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

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

Don_crissti ответ от Показать только текст между 2 соответствующими шаблонами ?

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

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

2
Léo Léopold Hertz 준영

как-то так у меня работает

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...

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

1
pataluc
Perl -lne 'print if((/abc/../mno/) && !(/abc/||/mno/))' your_file
1
Vijay

Я попытался использовать awk для печати строк между двумя шаблонами, в то время как pattern2 также совпадает с pattern1 . И линия pattern1 также должна быть напечатана. 

например . источник 

package AAA
aaa
bbb
ccc
package BBB
ddd
eee
package CCC
fff
ggg
hhh
iii
package DDD
jjj

должен иметь выход

package BBB
ddd
eee

Где pattern1 - package BBB, pattern2 - package \w*. Обратите внимание, что CCC не является известным значением, поэтому не может быть буквально сопоставлено.

В этом случае ни @scai awk '/abc/{a=1}/mno/{print;a=0}a' file, ни @fedorqui awk '/abc/{a=1} a; /mno/{a=0}' file не работают для меня.

Наконец, мне удалось решить это с помощью awk '/package BBB/{flag=1;print;next}/package \w*/{flag=0}flag' file, хаха

Немного больше усилий приводит к awk '/package BBB/{flag=1;print;next}flag;/package \w*/{flag=0}' file, для печати строки pattern2, то есть

package BBB
ddd
eee
package CCC
0
Weekend