sed - Удалить предыдущую и текущую строки на основе шаблона - PullRequest
1 голос
/ 23 апреля 2019

Я хочу удалить предыдущую строку и текущую строку на основе совпадения с шаблоном на следующей строке

Это мой sample.txt

This is test line 11
This is test line 999
This is test line 12
This is test line 13
This is test line 16
This is test line 999
This is test line 17
This is test line 18

Я хочу сопоставить шаблон 999 и удалитьи сама, и предыдущая строка

Я пытаюсь выполнить эту команду, но не получаю вывод

sed -Ene ':a;N;/999/{d;}; ba; P' sample.txt

Ответы [ 5 ]

3 голосов
/ 23 апреля 2019

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

sed 'N;/\n.*999/d;P;D' file

Открыть работающее окно из двух строк по всей длине файла.

Если вторая строка окна содержит 999, удалите обе строки.

В противном случае выведите первую строку окна, удалите первую строку и повторите.

Альтернативное решение для строки 1 или 2 или более смежных строк, содержащих 999:

sed -n ':a;$!N;/\n.*999/{:b;n;/999/bb;ba};/999/!P;D' file
2 голосов
/ 23 апреля 2019

попробовал на GNU SED

 sed -Ez 's/[^\n]*\n[^\n]*999\n//g' sample.txt
1 голос
/ 23 апреля 2019

Более подробный пример ввода:

$ cat file
This is test line 999
This is test line 11
This is test line 999
This is test line 12
This is test line 13
This is test line 999
This is test line 999
This is test line 999
This is test line 14
This is test line 15
This is test line 16
This is test line 999
This is test line 17
This is test line 18

Попробуйте:

$ cat tst.awk
$NF == 999 {
    prev = ""
    next
}
{
    printf "%s", prev
    prev = $0 ORS
}
END {
    printf "%s", prev
}

$ awk -f tst.awk file
This is test line 12
This is test line 14
This is test line 15
This is test line 17
This is test line 18

или, если вы предпочитаете краткость, а не ясность:

$ awk '$NF==999{p="";next} {printf "%s",p; p=$0 ORS} END{printf "%s",p}' file
This is test line 999
This is test line 11
This is test line 999
This is test line 12
This is test line 13
This is test line 999
This is test line 999
This is test line 999
This is test line 14
This is test line 15
This is test line 16
This is test line 999
This is test line 17
This is test line 18

Обратите вниманиечто вышеприведенное будет работать, даже если какая-то другая часть вашей строки, кроме последнего поля, содержала 999 или если последнее поле как 9999 вместо вашей цели 999, для нее не требуется писать 999 /проверено несколько раз в скрипте, если вы хотите проверить, скажем, 3-е поле в строке вместо последнего, вы можете просто изменить $NF на $3 =, если вы хотите проверить всю строку на регулярное выражениевы просто изменили бы $NF==999 на /999/, это будет работать, даже если ваша целевая строка содержит метасимволы регулярных выражений, и будет работать в любом awk в любой оболочке в любом окне UNIX.

1 голос
/ 23 апреля 2019

Для решения sed 1 , которое обрабатывает все крайние случаи (999 в первых 2 рядах или последовательных строках 999):

  sed '
    1{
      /999/d  # Special case needed for line 1. Delete if it contains 999.
    }
    $!N     # Append next line. $!N stops exit w/o printing at EOF.
    /999/d  # If pattern space contains 999, d & begin next cycle.
    P       # If we get to here, there is no 999. Print to first newline.
    D       # Delete to first newline.                                   
  ' FILE

Выход:

This is test line 12
This is test line 13
This is test line 17
This is test line 18

1 Протестировано на BSD (Mac OS X) и GNU sed.

1 голос
/ 23 апреля 2019

Не могли бы вы попробовать следующее (если все в порядке с awk).

awk 'prev && $NF!=999{print prev ORS FNR,$0;prev="";next} $NF==999{prev=""} $NF!=999{prev=FNR FS $0}'  Input_file

Или, если у вас четное количество строк, и вы хотите позаботиться о печати последнего нечетного четного.

awk 'prev && $NF!=999{print prev ORS FNR,$0;prev="";next} $NF==999{prev=""} $NF!=999{prev=FNR FS $0} END{if(prev){print prev}}'  Input_file
...