Como substituir um código multilinha por sed?

Como substituir um código multilinha por sed?

Eu tenho um arquivo grande que contém caracteres especiais. Há um código de várias linhas que desejo substituir por sed.

Esse:

  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"

Precisa se transformar nisso:

text = ""

Tentei o seguinte código, mas sem sorte:

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

Não substitui nada e não exibe nenhuma mensagem de erro

Tenho brincado com ele, mas tudo que tento não funciona.

Responder1

Perl para o resgate:

perl -i~ -0777 -pe 's/text = "[^"]+"/text = ""/g' input-file
  • -i~irá editar o arquivo "no local", deixando uma cópia de backup
  • -0777lê o arquivo inteiro de uma vez, não linha por linha

A substituição s///funciona de forma semelhante ao sed (ou seja, corresponde text = "seguida por qualquer coisa, exceto aspas duplas, muitas vezes até aspas duplas), mas neste caso, funciona em todo o arquivo.

Responder2

Você tem que verificar o espaço do padrão e continuar puxando a Nlinha ext se ela não corresponder, por exemplo

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

com gnu sedvocê pode escrevê-lo como

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

Porém, isso não é muito eficiente, é melhor apenas selecionar o range /text = "/,/"/, modificar a primeira linha e excluir o resto:

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)

novamente, gnu sedvocê pode escrevê-lo como uma linha:

sed '/text = "/,/"/{/text = "/!d;s/\\/"/}' infile

Responder3

Pessoalmente, eu faria isso em Perl. Se pudermos assumir que não há "antes do fechamento ", você pode fazer:

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

Ele -0engole o arquivo inteiro, lendo-o na memória. O -pmeio é "imprimir todas as linhas (aqui, uma "linha" será o arquivo inteiro) após aplicar o script fornecido por -e". O script em si é um operador de substituição simples. Ele irá capturar a string textseguida por 0 ou mais caracteres de espaço em branco, um =e 0 ou mais espaços em branco novamente ( text\s*=\s*) e salvá-la como $1. Em seguida, ele substituirá o padrão capturado, bem como a string mais curta entre aspas que encontrar, pelo padrão ( $1) e "". A sbandeira .combina novas linhas.

informação relacionada