Remplacement SED sur plusieurs lignes

11

J'essaie de trouver ces trois lignes:

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

et remplacez-les par:

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

Quand j'essaye

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

Il ne le trouve pas, j'ai également essayé de le mettre \ n, mais cela n'a toujours pas fonctionné:

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

Ceux-ci ne génèrent aucune erreur, mais ne décommentent pas la ligne. Tout conseil serait utile merci!

Doug Molineux
la source

Réponses:

6

sed lit chaque ligne tour à tour, donc elle ne correspondra jamais à un modèle multiligne à moins que vous ne la poussiez dans la bonne direction. La Ncommande lit une ligne de l'entrée et l'ajoute à l'espace de motif.

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

Sans doute, si vous avez besoin d'une commande autre que s, alors vous devriez passer de sed à awk ou perl. Voici un extrait de Perl légèrement plus flexible qui gère les commentaires multilignes de manière plus générale.

perl -i -pe '
    if (/<!--/) { $_ .= <> while !/-->/;
        s[<!--\n(<Connector port="8009" protocol="AJP/1\.3" redirectPort="8443" />)\n-->][$1];
    }' /myfile.xml
Gilles 'SO- arrête d'être méchant'
la source
6

Sed fonctionne ligne par ligne. Il peut être fait pour fonctionner sur plusieurs lignes, mais il n'a pas été conçu de cette façon - et à mon avis, il apparaît clairement lorsque vous essayez d'utiliser comme ça. Mais si vous décidez de suivre cette voie, vous devrez probablement utiliser des registres. Consultez certaines des solutions de /programming/1251999/sed-how-can-i-replace-a-newline-n pour voir comment cela peut être fait.

Je préfère utiliser perl au lieu de sed pour ce genre de tâche (orientée sur plusieurs lignes, je veux dire). Le passe-partout que vous devez ajouter avant la recherche et le remplacement ( BEGIN...) n'est pas évident, mais l'expression régulière me semble plus propre:

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

Ou, en utilisant le regroupement pour raccourcir l'expression et pour vous permettre d'y utiliser une expression régulière:

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

Il devrait fonctionner à la fois sur les occurrences avec et sans sauts de ligne entre les marqueurs de commentaire et le code à ne pas commenter.

Adapté de:

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

Eduardo Ivanec
la source
Merci pour votre aide, on dirait que c'est une douleur, j'ai décidé d'utiliser une solution de contournement
Doug Molineux
3

Voici une description des commandes multilignes dans SED: http://docstore.mik.ua/orelly/unix/sedawk/ch06_01.htm

C'est une douleur dans le cul. Vous voudrez peut-être suivre les conseils d'Eduardo et les utiliser à la perl -i -p -eplace.

Hyppy
la source
Je ne créerais pas de lien vers des copies non autorisées de matériel protégé par des droits d'auteur.
Mark Wagner
1
  • /<\!--/ : chaîne correspondante
  • :X : c'est une étiquette pour la commande de branche "b"
  • /-->/ : chaîne correspondante
  • s@...@...@p : supprimer "<! -", "->" et imprimer le résultat
  • d : supprimer l'espace de motif et commencer un nouveau cycle
  • N : sinon correspondre avec / -> / puis ajouter une ligne
  • bX : branche vers: étiquette X
  • p : affiche simplement une chaîne qui ne correspond pas à / <! - /

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

et cette deuxième méthode est une simple substitution de copier-coller textuellement pour les fichiers texte habituels de petite taille (besoin d'un fichier de script 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
la source
1) Merci pour votre réponse. 2) L'insertion uniquement d'extraits de code n'est pas vraiment acceptable, il serait préférable que vous expliquiez ce qu'elle fait et comment.
peterh