Substituição do SED em várias linhas

11

Estou tentando encontrar essas três linhas:

<!--
<Connector port="8009" protocol="AJP/1.3" redirectPort="8443" />
-->

e substitua-os por:

<Connector port="8009" protocol="AJP/1.3" redirectPort="8443" />

Quando eu tento

sudo sed -i 's:<!-- <Connector port="8009" protocol="AJP/1.3" redirectPort="8443" /> -->:<Connector port="8009" protocol="AJP/1.3" redirectPort="8443" />:' /myfile.xml

Não encontra, tentei também colocar \ n, mas ainda não funcionou:

sudo sed -i 's:<!--\n <Connector port="8009" protocol="AJP/1.3" redirectPort="8443" />\n -->:<Connector port="8009" protocol="AJP/1.3" redirectPort="8443" />:' /myfile.xml

Isso não gera erros, apenas não descomenta a linha. Qualquer conselho ajudaria obrigado!

Doug Molineux
fonte

Respostas:

6

O sed lê cada linha sucessivamente, para que nunca corresponda a um padrão de múltiplas linhas, a menos que você o mova na direção certa. O Ncomando lê uma linha da entrada e a anexa ao espaço do padrão.

sed -i -e '/^<!--$/ {
    N; /\n<Connector port="8009" protocol="AJP\/1\.3" redirectPort="8443" \/>$/ {
        N; /\n-->$/ {
            s/^<!--\n//; s/\n-->$//
        }
    }
}' /myfile.xml

Indiscutivelmente, se você precisar de um comando que não seja s, deve mudar de sed para awk ou perl. Aqui está um snippet Perl um pouco mais flexível que lida com comentários de várias linhas de uma maneira mais geral.

perl -i -pe '
    if (/<!--/) { $_ .= <> while !/-->/;
        s[<!--\n(<Connector port="8009" protocol="AJP/1\.3" redirectPort="8443" />)\n-->][$1];
    }' /myfile.xml
Gilles 'SO- parar de ser mau'
fonte
6

Sed trabalha linha por linha. Ele pode ser feito para funcionar em várias linhas, mas não foi projetado dessa maneira - e, na minha opinião, definitivamente mostra quando você tenta usar dessa maneira. Mas se você decidir seguir esse caminho, provavelmente precisará usar registros. Verifique algumas das soluções em /programming/1251999/sed-how-can-i-replace-a-newline-n para ver como isso pode ser feito.

Eu prefiro usar perl em vez de sed para esse tipo de tarefa (com várias linhas, quero dizer). O clichê que você deve adicionar antes da pesquisa e substituição ( BEGIN...) não é óbvio, mas o regex parece mais limpo para mim:

perl -i.bak -pe 'BEGIN{undef $/;} s/<!--string-->/string/smg' file.xml

Ou, usando o agrupamento para encurtar a expressão e permitir que você use uma regex lá:

perl -i.bak -pe 'BEGIN{undef $/;} s/<!--(string_or_regex)-->/\1/smg' file.xml

Ele deve funcionar tanto em ocorrências com e sem novas linhas entre os marcadores de comentários e o código a ser descomentado.

Adaptado de:

/programming/1030787/multiline-search-replace-with-perl

Eduardo Ivanec
fonte
Obrigado por sua ajuda, parece que é uma dor, eu decidi usar uma solução alternativa
Doug Molineux
3

Aqui está uma descrição dos comandos multilinhas no SED: http://docstore.mik.ua/orelly/unix/sedawk/ch06_01.htm

É uma dor no traseiro. Você pode seguir os conselhos de Eduardo e usá-lo perl -i -p -e.

Hyppy
fonte
Eu não vincularia a cópias não autorizadas de material protegido por direitos autorais.
Mark Wagner
1
  • /<\!--/ : string correspondente
  • :X : este é um rótulo para o comando de ramificação "b"
  • /-->/ : string correspondente
  • s@...@...@p : tira "<! -", "->" e imprime o resultado
  • d : exclua o espaço do padrão e inicie um novo ciclo
  • N : se não corresponder a / -> /, adicione uma linha
  • bX : ramificar para: rótulo X
  • p : basta imprimir uma string que não corresponda a / <! - /

sed -rn '
/<!--/ {
    :X
    /-->/ {
        s@<!--\s*(<.+/>)\s*-->@\1@p
        d
    }
    N
    bX
};p'

e esse segundo método é uma simples cópia e colagem de substituição literal de arquivos de texto de tamanho pequeno (é necessário um arquivo de script de shell)

#!/bin/bash

# copy & paste content that you want to substitute

AA=$( cat <<\EOF | sed -z -e 's#\([][^$*\.#]\)#\\\1#g' -e 's#\n#\\n#g'
<!--
<Connector port="8009" protocol="AJP/1.3" redirectPort="8443" />
-->
EOF
)

BB=$( cat <<\EOF | sed -z -e 's#\([&\#]\)#\\\1#g' -e 's#\n#\\n#g'
<Connector port="8009" protocol="AJP/1.3" redirectPort="8443" />
EOF
)

sed -z -i 's#'"${AA}"'#'"${BB}"'#g' *.xml   # apply to all *.xml files
mug896
fonte
1) Obrigado pela sua resposta. 2) Inserir apenas trechos de código não é realmente bom; seria muito melhor se você explicasse o que faz e como.
peterh - Restabelece Monica 15/01