Como substituir um código de múltiplas linhas por sed?

8

Eu tenho um arquivo grande com caracteres especiais. Existe um código de múltiplas linhas, que eu quero substituir por sed .

Isto:

  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 mensagens de erro

Eu tenho jogado com ele, mas tudo que eu tento não funciona.

    
por blade19899 19.02.2016 / 13:37

3 respostas

13

Perl para o resgate:

perl -i~ -0777 -pe 's/text = "[^"]+"/text = ""/g' input-file
  • -i~ editará o arquivo "no lugar", 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 em sed (isto é, corresponde a text = " seguido de qualquer coisa, menos de aspas duplas muitas vezes até aspas duplas), mas, neste caso, funciona no arquivo inteiro. >     

por 19.02.2016 / 13:47
5

Você precisa verificar o espaço padrão e continuar puxando a linha N 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 sed você pode escrevê-lo como

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

Isso não é muito eficiente, basta 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, com gnu sed você pode escrevê-lo como um verso:

sed '/text = "/,/"/{/text = "/!d;s/\/"/}' infile
    
por 19.02.2016 / 14:31
3

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

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

O -0 usa o arquivo inteiro, lendo-o na memória. O -p significa "imprimir 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 string text seguida por 0 ou mais caracteres em branco, um = e 0 ou mais espaços em branco novamente ( text\s*=\s* ) e salvará como $1 . Em seguida, ele substituirá o padrão capturado, bem como a string mais curta entre aspas que encontrar com o padrão ( $1 ) e "" . O s flag faz com que . correspondam às novas linhas.

    
por 19.02.2016 / 13:49