Bonjour
Je connais bien Perl et ses expressions régulières, mais j'utilise depuis quelques temps 'sed' quand j'ai besoin de faire des traitements simples.
Je rencontre quelques soucis avec l'utilisation d'expressions régulières multi-lignes avec sed.
Si j'ai bien compris, sed traite les lignes une par une, donc je peux faire tous les motifs de la Terre, je n'aurais jamais un remplacement de plusieurs lignes pour une seule.
ex: s/toto\ntiti/tata/
Y'a-t-il une syntaxe *simple* pour effectuer ce genre de remplacement avec sed ?
Merci d'avance
# multi lignes
Posté par Ramón Perez (site web personnel) . Évalué à 3.
Mais tu peux rajouter des lignes dans le buffer, avec par exemple la commande N qui va rajouter la ligne suivante.
Pour ton exemple, tu peux faire un truc du genre :
sed 'N;s/toto\ntiti/tata/'
[^] # Re: multi lignes
Posté par Degrémont Aurélien . Évalué à 1.
Merci pour la réponse, ca correspond tout à fait à ma question, mais il s'avère qu'en fait mon problème est un peu plus compliqué :)
Cette solution fonctionne très bien, pour 1 remplacement sur un flux, mais mon traitement comporte n remplacements, certains sur 2 ou 3 lignes, d'autres sur 1 seule (la majorité). Apparement, l'utilisation de la fonction N induit des décalages dans la lecture du buffer et sed 'oublie' certaines occurences.
Pour être plus simple, je vais vous donner un exemple concret de mes traitements. Je cherche à traduire des fichiers Dia ( http://www.gnome.org/projects/dia/ ) à la volée avec sed.
J'ai donc des fichiers Dia, en français, et je souhaite les passer en anglais. Les fichiers Dia se présentent sous la forme d'un flux XML compressé en gzip (pas obligatoire).
Un simple zcat donne le contenu suivant : Je cherche à traduire les textes <dia:string>...</dia:string> et j'utilise pour cela un script sed qui ressemble à ça : Apparement, le fait de rajouter les commandes 'N' décale le parsing réalisé par sed et je perd certains remplacements qui auraient du être fait. J'avoue que je ne suis pas à l'aise avec sed et ses manipulations de buffer... Une idée ?[^] # Re: multi lignes
Posté par BAud (site web personnel) . Évalué à 2.
ensuite, envisager de passer à perl (qui a des fonctions toutes faites mais qu'il faudra chercher)
[^] # Re: multi lignes
Posté par Degrémont Aurélien . Évalué à 2.
[^] # Perl
Posté par Arthur Accroc . Évalué à 4.
Pour la machine, c'est effectivement plus lourd (mais si tu n'as pas un 486 avec 8 Mo de mémoire ou un matériel embarqué, ça ne devrait pas être bloquant), mais pour toi, pas nécessairement :
perl -p0777e 's/toto\ntiti/tata/g' fichier
Voire éventuellement plus intéressant, sauf si tu es sûr que toto et titi sont tout le temps séparés par une fin de ligne :
perl -p0777e 's/toto\s+titi/tata/gs' fichier
Ainsi,
tyty toto titi tete
tete tutu toto
tititoto titi tyty
devient :
tyty tata tete
tete tutu tatatata tyty
Tiré de man perlrun :
-p indique à Perl de considérer votre programme comme entouré par [une] boucle, qui le fait itérer sur les noms de fichiers passés en arguments, un peu à la manière de sed.
-0[digits] indique le séparateur d'enregistrement en entrée ($/) en notation octale. [...] La valeur 0777, indique à Perl d'avaler les fichiers en entier car il n'y a pas de caractère avec cette valeur octale.
Tiré de man perlop :
s/MOTIF/REMPLACEMENT/egimosx
s Traitement de la chaîne comme étant une seule ligne.
(ainsi \s peut correspondre à \n).
« Le fascisme c’est la gangrène, à Santiago comme à Paris. » — Renaud, Hexagone
[^] # Script façon sed en Perl
Posté par Arthur Accroc . Évalué à 3.
#!/usr/bin/perl -p0777
s/toto\ntiti/tata/gs;
s/...
« Le fascisme c’est la gangrène, à Santiago comme à Paris. » — Renaud, Hexagone
[^] # Détail
Posté par Arthur Accroc . Évalué à 2.
#!/usr/bin/perl -p0777
s/toto\s+titi/tata/gs;
s/...
« Le fascisme c’est la gangrène, à Santiago comme à Paris. » — Renaud, Hexagone
[^] # Re: Détail
Posté par Degrémont Aurélien . Évalué à 1.
Ca me résout pas mal de mes soucis, les règles sont beaucoup plus claires, que des avantages :)... Si ce n'est que je lance un process Perl pour chaque traitement.
Je connais très bien Perl, mais je me force justement à éviter de l'utiliser quand il existe d'autres solutions beaucoup plus légère, éviter d'utiliser un bulldozer pour écraser une mouche. C'est un bon réflexe je pense.
Mais bon, pour cette fois, Perl gère bien mieux les multi-lignes que 'sed', alors, profitons s'en ! :)
Merci pour votre aide.
[^] # To Perl or not to Perl
Posté par Arthur Accroc . Évalué à 2.
Alors pourquoi pas plutôt faire un script unique, plus conséquent, qui fasse tous les traitements ?
Pour ma part, à l'inverse, c'est mon temps que j'essaie d'économiser plus que celui de la machine.
Aussi, je pars directement sur Perl. Comme ça, quand je m'aperçois qu'il est souhaitable de faire un traitement plus compliqué que prévu et que l'outil qui m'aurait semblé suffisant au départ ne l'est plus, eh bien je ne perds pas de temps à convertir ce que j'avais déjà fait en Perl, parce que ça y est depuis le départ.
Je ne suis pas convaincu que ce choix ait dans l'informatique actuelle autant de portée qu'il en aurait eu auparavant.
Pour égaler avec Perl la charge infligée sur un poste de travail par un navigateur web soit-disant léger comme Firefox ou par OpenOffice, ou sur un serveur par un truc "hyper-efficace" comme OpenLDAP, il faut vraiment que le traitement soit très lourd, ou alors qu'on l'ait programmé comme un pied. La lourdeur due au temps de lancement ou à l'encombrement mémoire de Perl par rapport à bash, sed ou awk est alors négligeable...
Je dis ça par expérience personnelle.
Sur le PIII 450 (avec 512 Mo quand même) que j'ai encore comme poste de travail pour quelques semaines, les trucs les plus lourds que j'utilise sont Firefox, xpdf et OpenOffice; la machine serait encore assez puissante pour tout le reste. Je n'ouvre généralement pas documents Word que je reçois en attachement de mail : la plupart du temps, l'intérêt du contenu ne vaut pas le temps que met OpenOffice à se lancer.
J'utilise OpenLDAP sur un serveur et je faisais sur l'annuaire un traitement nécessitant un nombre conséquent de requêtes assez lourdes. J'en ai eu marre que ça me charge le serveur pendant plusieurs minutes. Maintenant, je charge directement tout l'annuaire avec un dump au niveau du backend (donc en court-circuitant OpenLDAP) et je fais tous les traitements en interne de mon script Perl. C'est carrément plus rapide. Et encore j'ai utilisé par facilité les structures fournies d'origine par Perl (tableau associatif notamment), plutôt que des structures plus optimales dans ce cas (par exemple un arbre pour stocker l'annuaire). Sans importance : mes traitements sont encore nettement moins longs que le chargement de l'annuaire, pourtant pas plus long qu'une seule grosse requête sur OpenLDAP.
« Le fascisme c’est la gangrène, à Santiago comme à Paris. » — Renaud, Hexagone
Suivre le flux des commentaires
Note : les commentaires appartiennent à celles et ceux qui les ont postés. Nous n’en sommes pas responsables.