заменить две строки на одну в командной строке оболочки - PullRequest
2 голосов
/ 24 сентября 2011

Есть много вопросов о замене нескольких новых строк на один новый, но никто не работает для меня.
У меня есть файл:

first line
second line MARKER

third line MARKER
other lines

many other lines

Мне нужно заменить два новых строки (если онисуществует) после MARKER до одной новой строки.Файл результата должен быть:

first line
second line MARKER
third line MARKER
other lines

many other lines

Я пробовал sed ':a;N;$!ba;s/MARKER\n\n/MARKER\n/g' Неудачно.
sed полезен для однострочных замен, но имеет проблемы с символами новой строки.Он не может найти \n\n

Я пытался perl -i -p -e 's/MARKER\n\n/MARKER\n/g' Fail.
Это решение выглядит ближе, но кажется, что регулярное выражение не реагирует на \n\n.

Можно ли заменить \n\n только после MARKER и не заменять другие \n\n в файле?
Меня интересует однострочное решение, а не сценарии.

Ответы [ 7 ]

3 голосов
/ 24 сентября 2011

Я думаю, вы были на правильном пути.В многострочной программе вы загружаете весь файл в один скаляр и запускаете на нем следующую подстановку:

s/MARKER\n\n/MARKER\n/g

Хитрость заключается в получении однострочной строки для загрузки файла в многострочную систему.строка должна установить $/ в блоке BEGIN.Этот код будет выполнен один раз, прежде чем будет прочитан ввод.

perl -i -pe 'BEGIN{$/=undef} s/MARKER\n\n/MARKER\n/g' input
3 голосов
/ 24 сентября 2011

Ваше решение на Perl не работает, потому что вы ищете строки, содержащие две новые строки.Там нет такой вещи.Вот одно из решений:

perl -ne'print if !$m || !/^$/; $m = /MARKER$/;' infile > outfile

Или на месте:

perl -i~ -ne'print if !$m || !/^$/; $m = /MARKER$/;' file

Если вы загрузили весь файл в память, вы можете использовать

perl -0777pe's/MARKER\n\n/MARKER\n/g;' infile > outfile

или

perl -0777pe's/MARKER\n\K\n//g;' infile > outfile

Как указано выше, вы можете использовать -i~ для редактирования на месте.Удалите ~, если вы не хотите делать резервную копию.

2 голосов
/ 24 сентября 2011

AWK:

kent$  cat a
first line
second line MARKER

third line MARKER
other lines

many other lines

kent$  awk 'BEGIN{RS="\x034"} {gsub(/MARKER\n\n/,"MARKER\n");printf $0}' a
first line
second line MARKER
third line MARKER
other lines

many other lines
1 голос
/ 24 сентября 2011
0 голосов
/ 15 декабря 2011

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

 sed '/MARKER/,//{//!d}'

Пояснение:

Удаляет все строки между MARKER и сохраняет MARKER строк.

Или:

sed '/MARKER/{n;N;//D}'

Пояснение:

Прочитайте следующую строку после MARKER, затем добавьте строку после этого. Удалить предыдущую строку, если текущая строка MARKER.

0 голосов
/ 25 сентября 2011

Это можно сделать очень просто sed.

sed '/MARKER$/{n;/./!d}'
0 голосов
/ 25 сентября 2011
awk '
  marker { marker = 0; if (/^$/) next }
  /MARKER/ { marker = 1 }
  { print }
'
...