Как заменить многострочный код на sed?

9

У меня есть большой файл, в котором есть специальные символы. Там есть многострочный код, который я хочу заменить sed.

Эта:

  text = "\
    ------                                                           ------\n\n\
    This message was automatically generated by email software\n\
    The delivery of your message has not been affected.\n\n\
    ------                                                           ------\n\n"

Необходимо превратить в это:

text = ""

Я попробовал следующий код, но не повезло:

sed -i '/  text = "*/ {N; s/  text = .*affected.\./  text = ""/g}' /etc/exim.conf

Он ничего не заменяет и не отображает никаких сообщений об ошибках.

Я играл с этим, но все, что я пытаюсь, не работает.

blade19899
источник
Это должно быть sedили вы открыты для других инструментов? Может ли быть "внутри text=блока? Могут ли быть другие случаи text = в вашем файле? Всегда будет 4 строки текста или их будет больше / меньше?
Terdon
Предпочтительно sedили что-либо, что не требует установки на сервере CentOS. Из коробки инструменты
blade19899
@terdon В text = папке нет других , выход должен быть text = "". Файлы имеют 891 строчку кода. ТАК, нужно уважать другой текст.
blade19899
Вы хотите перезаписать файл или просто изменить вывод?
joH1
@ Moonstroke НЕТ ПЕРЕЗАПИСИ. Просто нужно заменить текст - как видно из моего вопроса - на text = "". Как видно из моего вопроса.
blade19899

Ответы:

15

Perl на помощь:

perl -i~ -0777 -pe 's/text = "[^"]+"/text = ""/g' input-file
  • -i~ отредактируем файл "на месте", оставив резервную копию
  • -0777 читает весь файл сразу, а не построчно

Подстановка s///работает так же, как в sed (т. Е. Она совпадает с text = "последующим чем угодно, кроме двойных кавычек много раз, вплоть до двойных кавычек), но в этом случае она работает на весь файл.

choroba
источник
5

Вы должны проверить пространство шаблона и продолжать тянуть в Nстроке ext, если она не совпадает, например

sed '/text = "/{              # if line matches text = "
:b                            # label b
$!N                           # pull in the next line (if not the last one)
/"$/!bb                       # if pattern space doesn't end with " go to label b
s/".*"/""/                    # else remove everything between the quotes
}' infile

с gnu sedвы можете написать это как

sed '/text = "/{:b;$!N;/"$/!bb;s/".*"/""/}' infile

Это не очень эффективно, лучше просто выбрать диапазон /text = "/,/"/, изменить первую строку и удалить остальные:

sed '/text = "/,/"/{            # in this range
/text = "/!d                    # delete all lines not matching text = "
s/\\/"/                         # replace the backslash with quotes (this is only
}' infile                       # executed if the previous d wasn't executed)

Опять же, gnu sedвы можете написать это в виде одной строки:

sed '/text = "/,/"/{/text = "/!d;s/\\/"/}' infile
don_crissti
источник
3

Лично я бы сделал это на Perl. Если мы можем предположить, что нет "до закрытия ", вы можете сделать:

perl -0pe 's/(text\s*=\s*)".*?"/$1""/s' file

-0Хлебает весь файл, чтение его в память. В -pозначает «печать каждую строку (здесь,„линия“будет весь файл) после применения сценария дается -e». Сам скрипт является простым оператором подстановки. Он будет захватывать строку, textза которой следуют 0 или более пробельных символов, =снова text\s*=\s*и 0 и более пробельных символов ( ), и сохранять ее как $1. Затем он заменит захваченный шаблон, а также самую короткую строку в кавычках, которую он найдет, на pattern ( $1) и "". sФлаг делает .матч новой строки.

Тердон
источник
исправление, -00читает в пунктах, а не весь файл ( ссылка ). Если текст в кавычках содержит пустую строку, то регулярное выражение не будет совпадать.
Гленн Джекман
@glennjackman аааа! Я всегда путаю их. , Вот почему я на самом деле дважды проверил, добавив дополнительный абзац и запустив perl -00ne 'print;exit'. И я все еще ошибаюсь в своем ответе! Спасибо, исправлено.
Terdon