Table des matières
mémo sed
Pas mal de scripts sur http://sed.sourceforge.net/grabbag/scripts/ (dont iso2html.sed)
Cette page existe en plus complet sur http://cli.asyd.net/home/filtres/sed
Une autre doc assez complète sur http://okki666.free.fr/docmaster/articles/linux130.html
Dans le “ Guide avancé d'écriture des scripts Bash”, la page sur les regex http://abs.traduc.org/abs-4.2.01-fr/ch17.html#regexref et celle sur sed http://abs.traduc.org/abs-4.2.01-fr/apc.html
Sans oublier le bon “Langages de scipts sous linux” de Christophe Blaess chez Eyrolles.
- sed -e expression : applique l'expression au flux d'entrée
- sed -ne expression : idem, mais n'affiche rien en sortie, sauf si on le précise avec p
- sed -i -e expression fichier : applique l'expression au fichier (pas besoin de préciser entrée sortie). Attention, pas de sauvegarde de l'ancien fichier (sauvegarde en .bak avec sed -i.bak -e '…'). le -i seul marche avec la version gnu de sed, avec la version bsd, une extension est obligatoire, et il faudrait mettre -i'' pour ne pas avoir de sauvegarde (pas testé).
expression est en général de la forme
- n commande : applique la commande à la ligne n
- n,m commande : : applique la commande aux lignes de n à m
- /pattern/ commande : applique la commande aux lignes qui vérifient le pattern
- /pattern/,/pattern2/ commande : applique la commande aux lignes qui se trouvent entre une ligne qui vérifie pattern et une autre qui vérifie pattern2
- /pattern/,$ : applique la commande entre la première ligne qui vérifie pattern (incluse) et la fin du fichier.
Commandes
- = : affiche le n° de la ligne
- a : ajoute des lignes, par exemple :
sed -e '/pattern/a\ ajout d'une ligne\ et d'une autre.\ La dernière à ajouter n'ayant pas d'antislash s/bla/bla/; # autre commande' < fichier_src > fichier_dest
- c : change des lignes complètes, ex (vire le corps des fonctions, blocs compris entre accolades ouvrantes/fermantes qui débutent une ligne, et remplace par “[… corps de la fonction …]”
sed -e '/^{/,/^}/c\ [... corps de la fonction ...]' < fichier.c > resume
- d : efface le buffer (et repart au début du script avec la ligne d'entrée suivante)
- D : efface le début du buffer jusqu'au premier \n et repart au début du script (avec une nouvelle ligne si le buffer a été vidé complètement).
- i : insère avant la ligne.
- l : idem p avec les caractères de contrôle
- n : passe à la ligne suivante (sans appliquer les commandes suivantes à la ligne courante) et y applique la commande suivante.
- N : charge la ligne suivante dans le buffer
- s/motif/remplacement/opt
- p : affiche la ligne
- P : affiche le début du buffer jusqu'au premier \n (il reste dans le buffer).
- q : quitte le script (sans analyser les lignes suivantes)
- y/car_src/car_dest/ : substitue des caractères par d'autres
rechercher/remplacer
s/search/replace/opt où opt peut être
- rien : la 1re occurence est remplacée
- g : toutes les occurences sont remplacées
- N : seule la Nième occurence est remplacée
- p : affiche la ligne si subtitution
- w fichier : envoie le résultat de la substitution dans un fichier
- I : insensible à la casse (extension GNU)
Caractères particulier pour le remplacement :
- \i ième référence arrière
- & chaine complète qui correspond au pattern
Holdspace
Il est aussi possible d'utiliser le “holdspace” (un buffer secondaire).
- P affiche la première ligne du pattern space.
- x échange les contenus du pattern space et du hold space.
- g remplace le contenu du pattern space par celui du hold space.
- G ajoute un caractère nouvelle ligne et le contenu du hold space au pattern space.
- h remplace le contenu du hold space par celui du pattern space.
- H ajoute un caractère nouvelle ligne et le contenu du pattern space au hold space.
- N ajoute un caractère nouvelle ligne et une nouvelle ligne de données au pattern space (s'il n'y a plus de données à lire, l'emploi de cette commande cause la fin du programme).
Exemples
Effacer les lignes qui suivent un pattern, mais pas celle du pattern
sed -e '/pattern/,$ { # on affiche la 1re p # on efface les suivantes :boucle d $! b boucle # $! est la négation de $, qui signifie la dernière ligne }'
Mais pour arriver au même résultat, cela paraît plus intelligent d'imprimer toutes les lignes jusqu'au pattern inclus (et pas les suivantes).
sed -ne '1,/pattern/ p'
Pour tout charger dans le buffer (pour du remplacement multilignes ensuite, à ne pas faire sur des fichiers de plus de qq ko)
{ :boucle N $! b boucle }
Récupérer les tailles d'images dans un mxml
#!/bin/sed -nf # script de parsing des mxml pour récupérer les png et leur taille # la taille peut être sur la ligne du Embed, mais pas toujours, et dans ce cas # elle est précisée par la balise précédente qui précise une taille # on cherche hauteur largeur /width=/ { # faut garder la ligne entière pour la suite (au cas où il y aurait aussi du embed dedans) => on mémorise en holdspace h # on remplace width par height car on ne connait pas l'ordre (on aura height en double, on se fout de l'ordre) # si on voulait distinguer width et height, il faudrait deux blocs comme celui-ci s#width=#height=# s#.*height="\([0-9]*\)".*height="\([0-9]*\)".*#\1 \2# # on passe ces deux nb en holdspace et on récupère la ligne initiale x } # on cherche une image /Embed('\/ressources\/medias\/images\// { s#.*@Embed('/ressources/medias/images\/\([^']*\)'.*#\1#; # on recupere le holdspace et les valeurs qui s'y trouvent sur une ligne sup G; # on vire le retour chariot qui s'y trouve s#\n# # # et on affiche p }
Virer les commentaires
sed est “greedy” (gourmand, il prend la plus longue chaîne qui correspond) et y'a pas moyen de mettre *? pour le rendre “ungreedy”, faut donc ruser…
sed -e '{ :boucle; N; $! b boucle;}; s#/\*[^\*]*\*/##g' < fichier
Ça marche pour virer les “/* bla bla */” mais ça garde du “/* bla * bla */”, on peut peaufiner en virant d'abord les * (on les remplaçe par une chaîne exotique dont on suppose qu'elle n'existe pas au préalable, on traite et on remet)
sed -e '{ :boucle; N; $! b boucle;}; s/\([^/]\)\*\([^/]\)/\1µ£µ£µ£\2/g; s#/\*[^\*]*\*/##g; s/µ£µ£µ£/\*/g' < fichier
Et si on veut aussi virer les commentaires qui suivent “#” et “//”, et les lignes vides, alors, on ajoute :
#!/bin/sed -f # on charge tout dans le buffer { :boucle; N; $! b boucle;}; # on remplace les * isolés, vire les commentaires /* */ et on remets nos * isolés s@\([^/]\)\*\([^/]\)@\1µ£µ£µ£\2@g; s@/\*[^\*]*\*/@@g; s@µ£µ£µ£@\*@g; # On vire ce qui suit # sur une ligne s@#[^\n]*@@g; # les lignes qui commencent par ; (esp avant éventuels) s@\n[ \t]*;[^\n]*@\n@g; # et par // s@\n[ \t]*//[^\n]*@\n@g; # les espaces et tabulations seules sur leur ligne s@\n[ \t]*\n@\n@g; # et \n multiples qui pourraient rester après la commande précédente s@[\n]\+@\n@g;
et dans un fichier d'alias ça donne (dans la définition de l'alias faut ajouter un \ devant $, \n et \t)
alias catsc='sed -e "{ :boucle; N; \$! b boucle;}; s@\([^/]\)\*\([^/]\)@\1µ£µ£µ£\2@g; s@/\*[^\*]*\*/@@g; s@µ£µ£µ£@\*@g; s@#[^\\n]*@@g; s@\\n[ \\t]*;[^\\n]*@\\n@g; s@\\n[ \\t]*//[^\\n]*@\\n@g; s@\\n[ \\t]*\\n@\\n@g; s@[\\n]\+@\\n@g;"'
Récupérer des initiales
On utilise l'expression '\<' qui désigne le début d'un mot dans les expressions étendues ('\>' désigne la fin d'un mot). Attention, c'est juste un délimiteur (pas de caractère dedans). On entend par “mot” un changement alphanumérique/non-alpha. (script utilisé dans claws-mail, cf http://ll.lairdutemps.org/linux/claws-mail#personnalisation_et_scripts)
sed -re ' # vire ce qui suit un < s'il est précédé d'au moins une lettre s/([a-zA-Z]+[^<]*)<.*/\1/; # vire ce qui suit @ s/(.*)@.*/\1/; # met en capitale la première lettre d'un mot et vire les caractères non tiret-espace-point qui suivent, pour chaque occurence rencontrée s/(\<.)[^- .]*/\U\1/g; # vire les caractères tiret-espace-point s/[- \."<]//g; # ajoute "> " à la fin de ce qui reste s/.*/&> /;'