OVH Cloud OVH Cloud

sed sauts de ligne, multiligne etc..

21 réponses
Avatar
Christophe PEREZ
Bonjour,

Une nouvelle fois parmi vous pour vous soumettre mon problème.

La raison :
Lorsque je passe les mails reçu d'une mailing-list vers mon serveur de
news local, j'ai régulièrement des erreurs de mailpost concernant un
nombre trop élevé de headers.
C'est en général à cause d'un nombre de X-Received trop important, et
surtout, découpé.
Et comme je n'ai jamais trouvé comme paramétrer pour qu'il en accepte
plus de 101 (headers), j'ai pensé faire un script bash qui me corrige ça.

Ça se présente sous la forme :
X-Received: ...
(espace ou tabulation)suite ligne
...
X-Received: ...
(espace ou tabulation)suite ligne
...
X-Received: ...
(espace ou tabulation)suite ligne
...

De plus, il peut y avoir d'autres headers entre ces X-Received

J'avais pensé, au préalable, remplacer le
'^(X-Received[^n]*)\n[esptab][esptab]*' par '\1 '
(esptab = Espace + Tabulation)
pour avoir tout sur un X-Received sur une ligne, puis à ne garder que les
3 premiers et 3 derniers (par exemple)

J'ai donc fait un
sed ':1;N;s/\(X-Received:[^\n]*\)\n[ \t][ \t]*/\1 /;t1'
mais il ne me traite pas toutes les lignes concernées...

Mais évidemment, tout ça c'est la théorie, et je ne parviens à rien de
concluant.

Bien que ne maîtrisant pas sed, je préfère encore une solution y
faisant appel, plutôt qu'une solution perl car avec perl, je serai bien
incapable de l'adapter ensuite.
Ceci dit, je suis tout à fait ouvert à n'importe quelle autre solution,
et c'est pour ça que j'ai détaillé la raison de ce script.

Merci d'avance.

--
Christophe PEREZ
Écrivez moi sans _faute !

10 réponses

1 2 3
Avatar
Christophe PEREZ
Le Tue, 18 May 2004 10:14:28 +0200, Jacques L'helgoualc'h a écrit:

Heu, désolé, il y a même un bug :/, j'avais testé avec autre
chose, il manque le point d'interrogation de ^(X-)?Received: si
tu veux traiter les deux ensemble ...


Je l'avais vuuuu ! :-))

Sinon, c'est juste un truc tout bête avec du GOTO.


Dit-il...

En ligne de commande, sed -nr 'le script', par exemple dans un
pipe sur les en-têtes dans un procmailrc. Tu peux virer les
commentaires, et aussi remplacer les sauts de ligne par des
points-virgules, ça fait un chouette one-liner imbittable.


ok, vu et compris.

Sinon, sed -nrf fichier_script, ou chmod +x fichier_script. Si


compris.

tu filtres le corps en même temps, supprime le « ;q » final,


ok, impec.

et essaie plutôt avec un « 1{le script sans ;q} ».


Et c'est censé changer quoi ?

Ensuite, tu peux attaquer une mbox avec « /^From /{le script sans ;q} »


ok, compris, mais c'est juste pour de la conversion entre réception
fetchmail et envoie sur ng par mailpost.

de rien, il suffit de lire un peu http://sed.sf.net/ ;)


Arf' En Anglais ? Déjà qu'en Français j'ai assez de mal comme ça...
J'ai suivi un temps un mailing en anglais (swsusp), mais je viens
d'arrêter car je ne pigeais rien, et surtout, même si j'avais du mal je
parvenais à y soumettre mes problèmes, mais je ne comprenais pas les
réponses, ou en tout cas pas suffisamment précisément ;-)

En même temps que le précédent, ou à part ?


Ah ben en même temps bien sûr !

C'est possible au début de la seconde boucle, tous les en-têtes sont là ...


Les entêtes oui, mais le script de traitement non :-))
Je vais essayer de voir.
Merci.

--
Christophe PEREZ
Écrivez moi sans _faute !

Avatar
Christophe PEREZ
Le Tue, 18 May 2004 17:15:38 -0400, Christophe PEREZ a écrit:

Je vais essayer de voir.


Tout ce que j'ai pu faire de plus logique (selon ma logique très perso de
sed) a été de rajouter, avant le "p" final :
:c
/^References:/s/<[^>]*>[ ]*/&/M7;Tg
/^References:[^n]*n/s/(<[^>]*>[ ]*)*//M4
tc
:g

[ ] = [espace tabulation]

mais évidemment, ça ne donne rien.


--
Christophe PEREZ
Écrivez moi sans _faute !

Avatar
Jacques L'helgoualc'h
Christophe PEREZ a dit :

Le Tue, 18 May 2004 10:14:28 +0200, Jacques L'helgoualc'h a écrit:

Heu, désolé, il y a même un bug :/, j'avais testé avec autre
chose, il manque le point d'interrogation de ^(X-)?Received: si
tu veux traiter les deux ensemble ...


Je l'avais vuuuu ! :-))


Tu vois que c'est lisible ;)

[...]

et essaie plutôt avec un « 1{le script sans ;q} ».


Et c'est censé changer quoi ?


Ben, ça ne filtrera que les en-têtes, en laissant le corps
intact (tu peux ensuite ajouter des filtres de pied de page).

Ensuite, tu peux attaquer une mbox avec « /^From /{le script sans ;q} »


ok, compris, mais c'est juste pour de la conversion entre réception
fetchmail et envoie sur ng par mailpost.


Ça dépend si tu filtres uniquement les en-têtes, ou tout le
message ; comment est lancé le filtre ?

de rien, il suffit de lire un peu http://sed.sf.net/ ;)


Arf' En Anglais ?


Il y a aussi du portugais, je crois :) ; bon, les trucs de base
sont dans le sed1line, le do_it_with_sed est lisible aussi ?

../..
--
Jacques L'helgoualc'h


Avatar
Jacques L'helgoualc'h
Christophe PEREZ a dit :
[...]

Tout ce que j'ai pu faire de plus logique (selon ma logique très perso de
sed) a été de rajouter, avant le "p" final :
:c
/^References:/s/<[^>]*>[ ]*/&/M7;Tg
/^References:[^n]*n/s/(<[^>]*>[ ]*)*//M4
tc
:g

[ ] = [espace tabulation]

mais évidemment, ça ne donne rien.


Ton /^References:/, il faudrait qu'il soit au tout début de la
ligne 1, ce qui n'est jamais le cas ; avec /nReferences:/ ou
/^References:/M ça marche (GNU sed) ...

... mais ta substitution n'est pas limitée aux références, elle
va s'attaquer à toutes les chaînes entre <> du tampon de
traitement ... il faut plutôt faire un truc du genre

s/(nReferences: (trois références gardées))la quatrième m'a tuer/1/

à répéter tant qu'on est au-dessus du total demandé ; il faut
aussi accepter (n[[:blank:]]+)? entre les références.

à+,
--
Jacques L'helgoualc'h

Avatar
Christophe PEREZ
Le Wed, 19 May 2004 10:52:38 +0200, Jacques L'helgoualc'h a écrit:

Ton /^References:/, il faudrait qu'il soit au tout début de la
ligne 1, ce qui n'est jamais le cas ; avec /nReferences:/ ou
/^References:/M ça marche (GNU sed) ...


Arg ! D'où ce fameux M que je ne comprenais pas.
Je ne le trouve ni dans le man de sed ni dans celui de perlre.

... mais ta substitution n'est pas limitée aux références, elle
va s'attaquer à toutes les chaînes entre <> du tampon de
traitement ... il faut plutôt faire un truc du genre


ah...

s/(nReferences: (trois références gardées))la quatrième m'a tuer/1/

à répéter tant qu'on est au-dessus du total demandé ; il faut
aussi accepter (n[[:blank:]]+)? entre les références.


j'ai plutôt mis (n*[[:blank:]]+)? car le saut de ligne n'est pas
systématique...

Et, après pas mal de relectures de ton post ;-), je suis arrivé à ça
qui semble fonctionner :
#!/bin/sed -nrf
:a
N;/n$/!ba
:b
s/^(X-)?Received:/&/M5;Tf
s/^(X-)?Received:[^n]*n([ t][^n]*n)*//M2
tb
:f

:c
/^References:/Ms/(n*[[:blank:]]+)?<[^>]*>/&/M5;Tg
s/^(References:[[:blank:]]?(<[^>]*>(n*[[:blank:]]+)?){2}<[^>]*>)(n*[[:blank:]]+)?<[^>]*>/1/M
tc
:g
p

Seul problème, c'est qu'il semblerait que la première ligne ne matche
pas puisque je me retrouve avec seulement 3 références.
J'ai fait des efforts pourtant, mais je ne vois pas mieux.

De plus, pour la 2ème ligne, je n'ai pas trouvé d'autre syntaxe pour
garder 3 références, les blancs/nl entre elles, et supprimer ce qui
suit, sans supprimer le dernier saut de ligne. J'aurais préféré
canoniser un peu plus.

--
Christophe PEREZ
Écrivez moi sans _faute !

Avatar
Christophe PEREZ
Le Wed, 19 May 2004 09:50:08 +0200, Jacques L'helgoualc'h a écrit:

Tu vois que c'est lisible ;)


euh... je l'ai lu quand j'ai vu que ça ne marchait pas ;-)

Ben, ça ne filtrera que les en-têtes, en laissant le corps
intact (tu peux ensuite ajouter des filtres de pied de page).


Mais je ne vois pas la différence entre sed -nr 'script' et sed -nr
1{script}

Les 2 sans le ";q" final bien sûr.

Ça dépend si tu filtres uniquement les en-têtes, ou tout le
message ; comment est lancé le filtre ?


Oui et non... en fait, je me débrouille comme je peux, et pour tout
expliquer, j'ai une commande procmail du genre :
|/usr/local/perso/script Balise|/usr/bin/mailpost -d local -a news
groupe_inn

Je passe donc le mot "Balise" (dépendant de la mailing) comme argument à
mon script afin d'en extraire [Balise] du sujet.

Mon script à moi est (devenu, car modifié suite à ce que j'ai appris
ici) :
#!/bin/bash
/bin/sed -nr "
:a
N;/n$/!ba
s/[[:blank:]](added by [^)]*)//
/^Subject:[[:blank:]]/Ms/[$1] //
/^Subject:[[:blank:]]/Ms/[Rr][Ee]([[0-9]*])*://
/^Subject:[[:blank:]]/Ms/ Re ://
/^Subject:[[:blank:]]$/Ms/[[:blank:]]/ Pas de Titre/
/^Message-Id:[[:blank:]]/My/àâäéèêëîïôöùûü/aaaeeeeiioouuu/
/^X-([ABCF][A-Z]{1,3}|Extensions):/Md :b
s/^(X-)?Received:/&/M5;Tf
s/^(X-)?Received:[^n]*n([ t][^n]*n)*//M2 tb
:f
p
"

Je passe par bash car je ne sais pas passer un argument à sed.

Il y a aussi du portugais, je crois :)


Pas mieux.

; bon, les trucs de base sont dans le sed1line, le do_it_with_sed est
lisible aussi ?


Ah...

--
Christophe PEREZ
Écrivez moi sans _faute !

Avatar
Jacques L'helgoualc'h
Christophe PEREZ a dit :

Le Wed, 19 May 2004 10:52:38 +0200, Jacques L'helgoualc'h a écrit:

Ton /^References:/, il faudrait qu'il soit au tout début de la
ligne 1, ce qui n'est jamais le cas ; avec /nReferences:/ ou
/^References:/M ça marche (GNU sed) ...


Arg ! D'où ce fameux M que je ne comprenais pas.
Je ne le trouve ni dans le man de sed ni dans celui de perlre.


C'est dans info sed. Perlre, non :)


[...]
Et, après pas mal de relectures de ton post ;-),


S'il n'y a que toi à me lire, autant continuer en privé...

je suis arrivé à ça qui semble fonctionner :
#!/bin/sed -nrf
:a
N;/n$/!ba
[...]

:c
/^References:/Ms/(n*[[:blank:]]+)?<[^>]*>/&/M5;Tg
s/^(References:[[:blank:]]?(<[^>]*>(n*[[:blank:]]+)?){2}<[^>]*>)(n*[[:blank:]]+)?<[^>]*>/1/M
tc
:g
p

Seul problème, c'est qu'il semblerait que la première ligne ne matche
pas puisque je me retrouve avec seulement 3 références.
J'ai fait des efforts pourtant, mais je ne vois pas mieux.


Dans ton test des références, la substitution bidon cherche la
5ème <adresse> dans *tous* les en-têtes (le /^References:/M
vérifie qu'il existe, c'est tout --- tu n'as plus une analyse
ligne par ligne après la première boucle, tous les en-têtes sont
empilés dans l'espace de travail.


De plus, pour la 2ème ligne, je n'ai pas trouvé d'autre syntaxe pour
garder 3 références, les blancs/nl entre elles, et supprimer ce qui
suit, sans supprimer le dernier saut de ligne. J'aurais préféré
canoniser un peu plus.


Moi j'ai ça (testé sur un seul exemple), qui filtre avec ou sans
corps :

#!/bin/sed -rf
1{
# avale tous les en-têtes (au moins un :)
:a;N;/n$/!ba
:b
# teste s'il y a trop de (X-)?Received:
s/^(X-)?Received:/&/M7;Tc
# si oui, supprime le premier superflu
s/^(X-)?Received:[^n]*n([ t][^n]*n)*//M4
# et remonte vérifier le compte
tb
a ERREUR: b
:c
# teste le nombre des References:
s/^References:((n?[[:blank:]])*<[^>]+>){7}/&/M
Td
# supprime la quatrième (regexp optimisable...)
s/(^References:((n?[[:blank:]])*<[^>]+>){3})((n?[[:blank:]])*<[^>]+>)/1/M
tc
a ERREUR: c
:d
# fin du traitement des en-têtes
}

Ce serait peut-être plus propre en nettoyant avec une référence
par ligne, mais bon, ça te fait un autre exercice ;)
--
Jacques L'helgoualc'h


Avatar
Jacques L'helgoualc'h
Christophe PEREZ a dit :
[...]

Mais je ne vois pas la différence entre sed -nr 'script' et sed -nr
1{script}


le second ne s'applique qu'à la première ligne (et celles
avalées par le N jusqu'à la première ligne vide).

Sans le 1{}, il s'appliquera aussi à chaque paragraphe du corps
(tu verrais la différence sur les en-têtes d'un message joint).

[...]

Mon script à moi est (devenu, car modifié suite à ce que j'ai appris
ici) :
#!/bin/bash
/bin/sed -nr "
:a
N;/n$/!ba
s/[[:blank:]](added by [^)]*)//


Mes (added by ...), c'est du spam.

Cf. mon autre message, tes substitutions vont être appliquées
partout !

/^Subject:[[:blank:]]/Ms/[$1] //
/^Subject:[[:blank:]]/Ms/[Rr][Ee]([[0-9]*])*://


tu as aussi le flag I ...

/^Subject:[[:blank:]]/Ms/ Re ://
/^Subject:[[:blank:]]$/Ms/[[:blank:]]/ Pas de Titre/


Avec un sujet vide, le premier caractère espace de la 1ère ligne
donne un « From Pas de Titre...».

/^Message-Id:[[:blank:]]/My/àâäéèêëîïôöùûü/aaaeeeeiioouuu/
/^X-([ABCF][A-Z]{1,3}|Extensions):/Md :b


;:b

s/^(X-)?Received:/&/M5;Tf
s/^(X-)?Received:[^n]*n([ t][^n]*n)*//M2 tb


;tb

:f
p
"

Je passe par bash car je ne sais pas passer un argument à sed.


Pas mieux... mais je préfère 'le script', et '"$1"' pour
restreindre bash au $1 que je veux interpréter. Sinon, c'est Awk
ou Perl.

à+,
--
Jacques L'helgoualc'h

Avatar
Christophe PEREZ
Le Wed, 19 May 2004 13:02:27 -0400, Christophe PEREZ a écrit:

Mon script à moi est (devenu, car modifié suite à ce que j'ai appris
ici) :


Et évidemment, je me rends compte qu'entre l'ancienne version du script,
et le script remodelé, il y a un sacré méli-mélo.

C'est donc devenu :
#!/bin/bash
/bin/sed -nr "
:a
N;/n$/!ba
s/[[:blank:]](added by [^)]*)//g
/^Subject:[[:blank:]]/Ms/[$1][[:blank:]]+//g
/^Subject:[[:blank:]]/Ms/[Rr][Ee]([[0-9]*])* *: *//g
s/^Subject:[[:blank:]]*$/Subject: Pas de Titre/M
/^Message-Id:[[:blank:]]/My/àâäéèêëîïôöùûü/aaaeeeeiioouuu/
s/^X-([ABCF][A-Z]{1,3}|Extensions):[^n]*//M
:b
s/^(X-)?Received:/&/M5;Tf
s/^(X-)?Received:[^n]*n([ t][^n]*n)*//M2
tb
:f
p
"

champ référence non encore traité.

PS : je poste ce correctif avant de me connecter à nouveau. Je ne sais
donc pas s'il y a déjà eu des réponses à ce post.

--
Christophe PEREZ
Écrivez moi sans _faute !

Avatar
Christophe PEREZ
Le Wed, 19 May 2004 22:45:18 +0200, Jacques L'helgoualc'h a écrit:

Sans le 1{}, il s'appliquera aussi à chaque paragraphe du corps
(tu verrais la différence sur les en-têtes d'un message joint).


Ah, ok oui, effectivement pas bon.
Mais comme je fais pour inclure ce 1{} dans mon script si je ne suis pas
en ligne de commande (oui, je sais, je suis versatile...)

Mes (added by ...), c'est du spam.


Pas moi, ça arrive pas mal sur les mailing que je reçois... Certainement
postés avec un webmail (wanadoo).

Cf. mon autre message, tes substitutions vont être appliquées
partout !


Argh...

/^Subject:[[:blank:]]/Ms/[$1] //
/^Subject:[[:blank:]]/Ms/[Rr][Ee]([[0-9]*])*://


tu as aussi le flag I ...


Ah, oui, bien sûr...

/^Subject:[[:blank:]]/Ms/ Re ://
/^Subject:[[:blank:]]$/Ms/[[:blank:]]/ Pas de Titre/


Avec un sujet vide, le premier caractère espace de la 1ère ligne
donne un « From Pas de Titre...».


Argh... donc ça ne tient pas compte de mon premier
/^Subject:[[:blank:]]$/M ??

;:b
;tb


Zut, c'était une recomposition de pan qui avait mis ça sur la même
ligne sans que je m'en aperçoive, mais dans mon script, c'est sur une
ligne séparée.

Pas mieux... mais je préfère 'le script', et '"$1"' pour
restreindre bash au $1 que je veux interpréter.


Pas compris là...


--
Christophe PEREZ
Écrivez moi sans _faute !


1 2 3