Удаление N подходящих шаблонов с помощью sed, awk, perl и т. Д. - PullRequest
2 голосов
/ 29 мая 2019

У меня такая ситуация, файл содержит

abcd
line1
line2
line3
vwxyz
abcd
vwxyz
abcd
vwxyz
abcd
vwxyz
line4
line5

Я хотел бы удалить, когда найду подходящие 2 строки из

abcd
vwxyz

необходимо удалить, чтобы оно стало

abcd
line1
line2
line3
vwxyz
line4
line5

Я выполнил поиск по многочисленным предложениям в стеке потока при сопоставлении с образцом, но никогда не встречал сопоставления с шаблоном из 2 строк

У меня есть товарищ sed -i '/abcd|vwxyz/d' file1, но это не сработало, как ожидалось ...

Любая помощь приветствуется с помощью awk, sed, perl, pyhon и т. Д.

Ответы [ 6 ]

2 голосов
/ 29 мая 2019

В Perl самое простое решение - загрузить весь ввод в память.

perl -0777pe's/abcd\nvwxyz\n//g'

Если вы читаете строку за раз, общим решением проблем такого типа является сохранение буфера прошлых строк.

if (!eof()) {
   my @buf = scalar(<>);
   while (<>) {
      if ($buf[-1] =~ /^abcd$/ && /^vwxyz$/) {
         @buf = ();
      } else {
         print(shift(@buf));
         push(@buf, $_);
      }
   }

   print @buf;
}
2 голосов
/ 29 мая 2019

Вы имеете в виду что-то вроде этого?

sed '/abcd/{N;/vwxyz/d}' yourdata.file

Объяснение

/abcd/    # search first Pattern
{
N;        # if match read next line
/vwxyz/d  # if second pattern match then delete line
}
2 голосов
/ 29 мая 2019

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

sed 'N;/^abcd\nvwxyz$/d;P;D' file

Создайте 2-строчное окно по всей длине файла и удалите это окно, если текущее окно соответствует требуемым строкам. В противном случае напечатайте / удалите первую строку окна и добавьте другую строку, повторите.

Это может быть расширено, чтобы соответствовать n строк:

sed ':a;N;s/[^\n]\+/&/2;Ta;/^abcd\nvwxyz$/d;P;D' file

обобщено на 2 строки:

Или:

sed ':a;N;s/[^\n]\+/&/3;Ta;/^line1\nline2\nline3$/d;P;D' file

для 3 строк и т. Д.

Альтернатива:

sed -z 's/^abcd\nvwxyz\n//mg' file
1 голос
/ 29 мая 2019

Немного более загадочно, чем хотелось бы, но с GNU awk для RS с несколькими символами:

$ awk -v RS='\nvwxyz\n' -v ORS= '!sub(/(^|\n)abcd$/,""){$0=$0 RT} 1' file
abcd
line1
line2
line3
vwxyz
line4
line5

К сожалению, если мы собираемся использовать решение на основе RS (в отличие от продолжения работы)2-строчный буфер или аналогичный), вот как это нужно сделать, чтобы разместить многострочную строку, появляющуюся в начале и / или конце файла и / или в повторяющихся блоках и / или начинаться / останавливаться в середине другоголиний.Его можно использовать как есть для произвольных длинных блоков строк:

awk -v RS='\nvwxyz\n' -v ORS= '!sub(/(^|\n)foo\nbar\netc\nabcd$/,""){$0=$0 RT} 1' file

или, если вы предпочитаете:

awk -v RS='\nbar\netc\nabcd\nvwxyz\n' -v ORS= '!sub(/(^|\n)foo$/,""){$0=$0 RT} 1' file
1 голос
/ 29 мая 2019

Не могли бы вы попробовать, учитывая, что ваш фактический Input_file такой же, как показанные образцы.

awk -v RS="" '{gsub(/abcd\nvwxyz/,"");gsub(/[[:space:]]+\n/,ORS)} 1' Input_file
0 голосов
/ 29 мая 2019

С awk, где вы определяете разделитель записей как 2 строки и просто печатаете каждую строку.

awk -v RS='abcd\nvwxyz\n' '{printf $0}' file.in 
abcd
line1
line2
line3
vwxyz
line4
line5

Решение Python:

import re

with open('file.in', 'r') as file:
    data = file.read()
    print(re.sub(r'(^|\n)abcd\nvwxyz(?=\n)','',data), end='')

вывод:

python3 filter_lines.py 
abcd
line1
line2
line3
vwxyz
line4
line5
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...