Как удалить совпадающую строку, строку выше и строку ниже, используя sed? - PullRequest
11 голосов
/ 18 мая 2009

У меня есть следующая последовательность, встречающаяся в файле несколько раз:

yyyy
xxxx
zzzz

У меня есть регулярное выражение, соответствующее xxxx. Всякий раз, когда есть совпадение, я хочу удалить эту строку, строку перед (например, yyyy) и строку после нее (например, zzzz). Как я могу использовать sed для этого?

Ответы [ 7 ]

13 голосов
/ 20 мая 2009

Хитрость заключается в сохранении последней строки, видимой в «пробел».

sed -n '
/^xxxx/{n
        n
        x
        d
       }
x
1d
p
${x
  p
 }
' <input file>

Начиная с x - поменяйте местами текущую строку ввода с пробелом удержания (x), затем для первой строки ничего не печатайте (1d), последующие строки выводят строку, только что замененную из удержание пробела (p), в последней строке снова замените пробел удержания и выведите то, что было в нем ($x{x p}. Остается, что делать, когда мы попадаем в целевую строку (начиная с /^xxxx/) - читать следующие два линии в пространство образца (n n) и поменяйте пространство образца с пространством удержания (x) - это оставляет пространство удержания со следующей строкой, которую мы хотим напечатать, и пространство образца со строкой перед соответствием, которое мы не хотим, поэтому мы бросаем это (d)

1 голос
/ 18 мая 2009

Вы можете проверить этот документ . Он охватывает использование sed для работы с несколькими строками.

0 голосов
/ 05 июля 2015

Вы можете сначала перевернуть файл, использовать sed, чтобы удалить совпавшую строку и следующую строку (или строки, +Nd в команде sed), и, наконец, отменить результат обратно:

tac old.file | sed -e '/xxxx/,+1d' | tac > new.file
0 голосов
/ 23 ноября 2014

Вы можете использовать следующее:

sed -n '/xxxx/{N;s/.*//;x;d;};x;p;${x;p;}'

Это заменит 3 строки одной пустой строкой.

0 голосов
/ 16 марта 2012

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

echo -e "a\nyyyy\nxxxx\nzzzz\nb" | sed 'N;/^xxxx/M{/^xxxx/d;$!N;d};P;D'
a
b

Это сохраняет окно из двух строк в пространстве шаблона, и если требуемое регулярное выражение найдено в первой или второй строке, читает следующую строку, а затем удаляет все три строки. Крайние случаи - это когда регулярное выражение найдено в первой или последней строках, когда нет строки до / после. В этих случаях можно удалить только две строки.

Кстати, это решение могло выявить возможную ошибку в GNU sed. Флаг M адреса позволяет использовать метасимволы ^ и $ в качестве маркеров нулевой длины в регулярном выражении для начала и конца строки в многострочных строках. Пустой адрес // повторно использует ранее указанный адрес. Должен ли этот адрес содержать многострочный флаг? В настоящее время он, кажется, включает флаг, даже если он не указан, т.е.

sed 'N;/^xxxx/M{/^xxxx/d;$!N;d};P;D' file

дает другой (правильный) результат для:

sed 'N;/^xxxx/M{//d;$!N;d};P;D' file

, если xxxx появляется во второй строке файла.

0 голосов
/ 06 марта 2010
grep -v -f <(grep -1 "xxxx" file) file
0 голосов
/ 18 мая 2009

Вот как я бы сделал это на Perl, может быть, это поможет вам направиться на верный путь ... Удачи!

open(INFILE,"<in.txt");
my(@arrayOutBoundData, $skipNextLine)l
for (<INFILE>) {
    if (not $skipNextLine) {
        if (/^xxxx$/) {
            pop(@arrayOutBoundData);
            $skipNextLine = 1;
        } else {
            push(@arrayOutBoundData,$_);
        }
    }
$skipNextLine = 0
}

open(OUTFILE,">out.txt");
for (@arrayOutBoundData) {
    print OUTFILE;
}

(Не проверено, нет Perl в этой системе, пожалуйста, простите за сайт.)

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...