Удалить соответствующую n-ю строку до пустой строки в awk/sed/grep

Мне нужно удалить n-ю совпадающую строку в файле от совпадения до следующей пустой строки (т.е. один фрагмент текста с разделителями пустой строки, начинающийся с n-го совпадения).


person Oli Pescott    schedule 16.12.2010    source источник
comment
Думаю, я понял вопрос. Но, пример поможет мне ответить.   -  person dheerosaur    schedule 16.12.2010
comment
Отличные ответы на все. Большое спасибо.   -  person Oli Pescott    schedule 17.12.2010


Ответы (4)


Это удалит фрагмент текста, который начинается и заканчивается пустой строкой, начиная с четвертой пустой строки. Он также удаляет эти разделительные линии.

sed -n '/^$/!{p;b};H;x;/^\(\n[^\n]*\)\{4\}/{:a;n;/^$/!ba;d};x;p' inputfile

Измените первый /^$/, чтобы изменить начальное совпадение. Измените второй, чтобы изменить конечное совпадение.

Учитывая этот ввод:

aaa
---
bbb
---
ccc
---
ddd delete me
eee delete me
===
fff
---
ggg

Эта версия команды:

sed -n '/^---$/!{p;b};H;x;/^\(\n[^\n]*\)\{3\}/{:a;n;/^===$/!ba;d};x;p' inputfile

даст это как результат:

aaa
---
bbb
---
ccc
fff
---
ggg

Изменить:

Я удалил лишнюю инструкцию b из команд sed выше.

Вот версия с комментариями:

sed -n '      # don't print by default
  /^---$/!{   # if the input line doesn't match the begin block marker
    p;        # print it
    b};       # branch to end of script and start processing next input line
  H;          # line matches begin mark, append to hold space
  x;          # swap pattern space and hold space
  /^\(\n[^\n]*\)\{3\}/{    # if what was in hold consists of 3 lines
                           # in other words, 3 copies of the begin marker
    :a;       # label a
    n;        # read the next line
    /^===$/!ba;    # if it's not the end of block marker, branch to :a
    d};       # otherwise, delete it, d branches to the end automatically
  x;          # swap pattern space and hold space
  p;          # print the line (it's outside the block we're looking for)
' inputfile   # end of script, name of input file

Любой однозначный шаблон должен работать для маркеров начала и конца. Они могут быть одинаковыми или разными.

person Dennis Williamson    schedule 16.12.2010
comment
Не могли бы вы прокомментировать / разбить sed? - person Anders; 16.12.2010

perl -00 -pe 'if (/pattern/) {++$count == $n and $_ = "$`\n";}' file

-00 — прочитать файл в режиме «абзац» (разделитель записей — одна или несколько пустых строк)

$` — это специальная переменная Perl для «предварительного сопоставления» (текст перед шаблоном сопоставления).

person glenn jackman    schedule 16.12.2010

В АВК

/m1/  {i++};

(i==3)  {while (getline temp > 0 && temp != "" ){}; if (temp == "") {i++;next}};

{print}  

Преобразует это:

m1 1
first

m1 2
second

m1 3
third delete me!

m1 4
fourth

m1 5
last

в это:

m1 1
first

m1 2
second

m1 4
fourth

m1 5
last  

удаление третьего блока "m1"...

Запуск на ideone здесь

ХТХ!

person Dr. belisarius    schedule 16.12.2010

Обязательный awk-скрипт. Просто измените n=2 на то, каким должно быть ваше n-е совпадение.

n=2; awk -v n=$n '/^HEADER$/{++i==n && ++flag} !flag; /^$/&&flag{flag=0}' ./file

Вход

$ cat ./file
HEADER
line1a
line2a
line3a

HEADER
line1b
line2b
line3b

HEADER
line1c
line2c
line3c

HEADER
line1d
line2d
line3d

Выход

$ n=2; awk -v n=$n '/^HEADER$/{++i==n&&++flag} !flag; /^$/&&flag{flag=0}' ./file
HEADER
line1a
line2a
line3a

HEADER
line1c
line2c
line3c

HEADER
line1d
line2d
line3d
person SiegeX    schedule 16.12.2010