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

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

У меня есть большой файл, в котором есть специальные символы. Там есть многострочный код, который я хочу заменить на 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

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

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

решение1

Perl спешит на помощь:

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

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

решение2

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

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

решение3

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

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

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

Связанный контент