Как выбрать линии между двумя шаблонами маркеров, которые могут встречаться несколько раз с помощью 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
сделать это повторно до конца файла?
10 ответов
Использование 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, строка печатается.
Более подробное описание и примеры вместе со случаями, когда шаблоны либо показаны, либо нет, см. В разделе Как выбрать линии между двумя шаблонами?,
С помощью sed
:
sed -n -e '/^abc$/,/^mno$/{ /^abc$/d; /^mno$/d; p; }'
-n
опция означает не печатать по умолчанию.
Шаблон ищет строки, содержащие только abc
чтобы просто mno
и затем выполняет действия в { ... }
, Первое действие удаляет abc
линия; вторая mno
линия; и p
печатает оставшиеся строки. Вы можете расслабить регулярные выражения по мере необходимости. Любые линии за пределами диапазона abc
..mno
просто не печатаются.
Это может работать для вас (GNU sed):
sed '/^abc$/,/^mno$/{//!b};d' file
Удалить все строки, кроме строк, начинающихся с abc
а также mno
Из ссылок предыдущего ответа, тот, который сделал это для меня, запустив ksh на Solaris, был таким:
sed '1,/firstmatch/d;/secondmatch/,$d'
sed '/^abc$/,/^mno$/!d;//d' file
Гольф на два персонажа лучше, чем у Ппотонга {//!b};d
Пустые косые черты //
означают: "повторно использовать последнее использованное регулярное выражение". и команда делает то же самое, что и более понятное:
sed '/^abc$/,/^mno$/!d;/^abc$/d;/^mno$/d' file
Это похоже на POSIX:
Если RE пусто (т. Е. Шаблон не указан), sed должен вести себя так, как если бы было указано последнее RE, использованное в последней примененной команде (либо в качестве адреса, либо в качестве части замещающей команды).
Как -то так у меня работает
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 намного лучше / красивее, чем мое.
Don_crissti ответ от Показать только текст между 2 соответствующими шаблонами?
firstmatch="abc"
secondmatch="cdf"
sed "/$firstmatch/,/$secondmatch/!d;//d" infile
который намного эффективнее, чем приложение AWK, смотрите здесь.
perl -lne 'print if((/abc/../mno/) && !(/abc/||/mno/))' your_file
Это также можно сделать с помощью логических операций и операций увеличения/уменьшения флага:
awk '/mno/&&--f||f||/abc/&&f++' file
Я пытался использовать 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 's 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