Como substituir um código de várias linhas pelo sed?

9

Eu tenho um arquivo grande com caracteres especiais. Há um código de várias linhas lá, que eu quero substituir sed.

Este:

  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 = ""

Eu tentei o seguinte código, mas sem sorte:

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

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

Eu tenho brincado com isso, mas tudo o que tento não funciona.

blade19899
fonte
Precisa ser sedou você está aberto a outras ferramentas? Pode haver "dentro do text=bloco? Pode haver outros casos text = no seu arquivo? Sempre haverá quatro linhas de texto ou pode haver mais / menos?
terdon
De preferência sed, ou qualquer coisa que não exija instalação em um servidor CentOS. Ferramentas
prontas para uso
@terdon Não há outro text = na pasta, o resultado precisa ser text = "". Os arquivos possuem 891 linhas de código. Portanto, ele precisa respeitar o outro texto.
blade19899
você deseja sobrescrever o arquivo ou apenas modificar a saída?
JoH1
@ Moonstroke NENHUMA SUBSTITUIÇÃO. Ele só precisa substituir o texto - como visto na minha pergunta - por text = "". Como visto na minha pergunta.
blade19899

Respostas:

15

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
  • -0777 lê o arquivo inteiro de uma só vez, não linha por linha

A substituição s///funciona da mesma forma que no sed (ou seja, corresponde a text = "qualquer coisa, exceto aspas duplas muitas vezes até aspas duplas), mas, neste caso, funciona em todo o arquivo.

choroba
fonte
5

Você deve verificar o espaço do padrão e continuar puxando a Nlinha ext se 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 selecionar o intervalo /text = "/,/"/, modificar a primeira linha e excluir o restante:

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 escrever como uma linha:

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

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

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

Ele -0sorve o arquivo inteiro, lendo-o na memória. Os -pmeios "imprima todas as linhas (aqui, uma" linha "será o arquivo inteiro) depois de aplicar o script fornecido por -e". O script em si é um operador de substituição simples. Ele capturará a sequência textseguida por 0 ou mais caracteres de espaço em branco, =e 0 ou mais espaços de novo ( text\s*=\s*) e salvará como $1. Em seguida, ele substituirá o padrão capturado, bem como a string mais curta citada, pelo padrão ( $1) e "". A sbandeira .cria novas linhas de correspondência.

terdon
fonte
correção, -00lê parágrafos, não o arquivo inteiro ( ref ). Se o texto entre aspas contiver uma linha em branco, a regex não corresponderá.
Glenn Jackman
@glennjackman argh! Eu sempre confundo isso. . É por isso que eu realmente verifiquei adicionando um parágrafo extra e executando perl -00ne 'print;exit'. E ainda coloco o errado na minha resposta! Obrigado, corrigido agora.
terdon