Удаление n строк в обоих направлениях и совпадение в sed?
Удаление совпадения и двух строк перед тем, как оно заработает:
sed -i.bak -e '/match/,-2d' someCommonName.txt
Удаление совпадения и двух строк после его работы:
sed -i.bak -e '/match/,+2d' someCommonName.txt
Но удаление совпадения, две строки после него и две строки до него не работает?
sed -i.bak -e '/match/-2,+2d' someCommonName.txt
sed: -e expression #1 unknown command: `-'
Это почему?
4 ответа
У меня нет полного решения, но набросок: sed
это довольно простой инструмент, который не делает две вещи одновременно. Мой подход будет бежать sed
удалив две строки после шаблона, но сохранив сам шаблон. Результат может быть затем передан sed
еще раз, чтобы удалить шаблон и две строки перед.
sed
работает по ряду адресов. Это означает одно или два выражения, а не три.
/match/
адрес, который соответствует регулярному выражению
-2
адрес, который указывает две строки перед
+2
адрес, который определяет две строки после
Следовательно:
/match/,-2
это диапазон, который определяет соответствие строки match
до двух строк раньше.
/match/-2,+2d
с другой стороны, включает в себя три адреса, и, следовательно, не имеет смысла.
Чтобы удалить две строки до и после шаблона, я бы порекомендовал что-то вроде этого ( изменено из этого ответа):
sed -n "1N;2N;/\npattern$/{N;N;d};P;N;D"
Это сохраняет 3 строки в буфере и читает файл. Когда шаблон находится в последней строке, он читает еще две строки и удаляет все 5. Обратите внимание, что это не будет работать, если шаблон находится в первых двух строках файла, но это начало.
sed -i .bak '/match/,-2 {/match/!d;};/match/,+2d' YourFile
попробуйте это (не могу проверить здесь, -2
не доступно в моей версии sed)
FWIW это то, как я действительно буду делать работу (просто измените b
а также a
значения для удаления разного количества строк до / после match
найден):
$ cat file
1
2
3
4
5 match
6
7
8
9
$ awk -v b=2 -v a=2 'NR==FNR{if (/match/) for (i=(NR-b);i<=(NR+a);i++) skip[i]; next } !(FNR in skip)' file file
1
2
8
9
$ awk -v b=3 -v a=1 'NR==FNR{if (/match/) for (i=(NR-b);i<=(NR+a);i++) skip[i]; next } !(FNR in skip)' file file
1
7
8
9
Обратите внимание, что в приведенном выше предположении предполагается, что когда в окне удаления появляются 2 "совпадения", вы хотите основывать удаления на исходном вхождении, а не на том, что произойдет после того, как будет найдено первое совпадение, что приведет к удалению 2-го совпадения:
$ cat file2
1
2
3
4 match
5
6 match
7
8
9
$ awk -v b=2 -v a=2 'NR==FNR{if (/match/) for (i=(NR-b);i<=(NR+a);i++) skip[i]; next } !(FNR in skip)' file2 file2
1
9
в отличие от выхода:
1
7
8
9
после удаления 2 строк после первого match
удалил 2-й match
и поэтому 2 строки после ТО не будут удалены, так как они больше не находятся в пределах 2 строк после match
,
Что-то еще, чтобы рассмотреть:
$ diff --changed-group-format='%<' --unchanged-group-format='' file <(grep -A2 -B2 match file)
1
2
8
9
$ diff --changed-group-format='%<' --unchanged-group-format='' file2 <(grep -A2 -B2 match file2)
1
9
При этом используются bash и GNU diff 3.2, idk, если / какие другие оболочки / различия будут поддерживать эти конструкции / опции.