Avertissement :
La version originale de cet article a été publiée sur IBM developerWorks
et est la propriété de Westtech Information Services. Ce document est une
traduction de la mise à jour de la version originale de l'article
réalisée par l'équipe de documentation Gentoo et contient quelques
améliorations proposées par l'équipe de documentation de Gentoo Linux.
Ce document n'est pas activement maintenu.
|
Sed par l'exemple — Première partie
1.
Prise en main de Sed, puissant éditeur UNIX
Le choix de l'éditeur
Dans le monde UNIX, nous disposons de beaucoup d'options quand il s'agit
d'éditer des fichiers. Il vous suffit de réfléchir et vous verrez des noms comme
vi, emacs ou jed vous venir à l'esprit, mais ce ne sont que des exemples parmi
d'autres. Nous avons tous un éditeur de texte favori (accompagné de raccourcis
claviers adaptés à vos habitudes) que nous avons appris à utiliser et que nous
aimons. Avec notre éditeur bien aimé nous pouvons réaliser n'importe quelle
tâche d'administration liée à la programmation ou à l'administration UNIX.
Si les éditeurs interactifs sont puissants, ils ont aussi des limitations. Si
leur nature interactive peut être une force, cela peut aussi se révéler être une
faiblesse. Prenez par exemple une situation dans laquelle vous devez effectuer
des modifications similaires sur un groupement de fichiers. Vous pouvez lancer
instinctivement votre éditeur favori et réaliser une grosse quantité d'éditions
de fichiers à la main, opération longue et répétitive. Mais il existe un
meilleur moyen.
Utiliser Sed
Ce serait bien si nous pouvions automatiser le processus d'édition des fichiers
et ainsi pouvoir les éditer en ligne de commande, voire même écrire des scripts
qui permettent d'effectuer des modifications sophistiquées sur des fichiers
existants. Heureusement pour nous, dans ce genre de situation, il existe une
solution. Cette solution s'appelle Sed.
Sed est un éditeur de flux léger inclus dans presque tous les systèmes UNIX,
notamment Linux. Sed dispose de nombreuses fonctionnalités intéressantes. Tout
d'abord, il est très léger, généralement plusieurs fois plus petit que votre
éditeur préféré. Ensuite, comme Sed est un éditeur de flux, il peut éditer les
données qu'il reçoit depuis l'entrée standard stdin ou depuis un
« pipe ». Vous n'avez donc pas besoin d'avoir les données sauvées dans
un fichier pour pouvoir les éditer. Comme les données peuvent être traitées en
ligne de commande, il est très facile d'utiliser Sed dans une longue ligne de
commande d'un script Shell. Essayez donc d'en faire autant avec votre éditeur
favori.
GNU sed
Heureusement pour nous autres utilisateurs de Linux, l'une des meilleures
versions de Sed existantes se trouve être GNU sed, actuellement dans sa version
3.02. Toutes les distributions Linux contiennent GNU sed ou, du moins, devraient
le contenir. GNU sed est populaire non seulement parce que ses sources peuvent
être distribuées librement, mais aussi parce qu'il dispose de nombreuses
extensions efficaces et sympathiques vis-à-vis du standard POSIX. GNU sed ne
souffre pas des nombreuses limitations que l'on trouve dans les récentes
solutions propriétaires de Sed, comme, par exemple, une limite sur la longueur
des lignes (GNU sed gère avec aisance les lignes de toutes tailles).
La version GNU sed la plus récente
Lors de mes recherches pour écrire cet article, j'ai remarqué que beaucoup de
fans de Sed sur Internet faisaient référence à GNU sed 3.02a. Curieusement je
n'arrivais pas à trouver cette version sur ftp://ftp.gnu.org (voir
les Ressources de cet article pour obtenir les
liens), il m'a fallu donc chercher ailleurs. Je l'ai trouvée sur
ftp://alpha.gnu.org, dans le répertoire /pub/sed. J'ai
téléchargé avec joie cette nouvelle version, l'ai installée, pour me rendre
compte quelques minutes plus tard que la version de Sed la plus récente était la
3.02.80, que vous pouvez trouver à côté de la 3.02a, sur
ftp://alpha.gnu.org. Après avoir installé GNU sed 3.02.80, j'étais
prêt à faire mes expérimentations.
Le bon Sed
Dans cette série d'articles, nous utiliserons GNU sed 3.02.80. Quelques-uns
(mais très peu) des exemples les plus avancés que vous trouverez plus loin dans
ces articles ne fonctionnent pas avec GNU sed 3.02 ou 3.02a. Si vous utilisez
une version de Sed non GNU, le résultat peut varier. Pourquoi donc ne pas
prendre le temps d'installer GNU sed 3.02.80 dès maintenant ? Vous serez
alors non seulement prêt pour la suite des articles, mais vous pourrez également
vous vanter d'avoir la meilleure version de Sed qui existe !
Sed par l'exemple
Sed fonctionne en effectuant toutes les opérations d'édition (des
« commandes ») spécifiées par l'utilisateur sur la ligne de commande.
Sed est un de ces outils qui ne traitent qu'une ligne à la fois. Ainsi, les
commandes seront appliquées sur chaque ligne, dans l'ordre. Il écrit le résultat
sur la sortie standard (stdout) puis passe à la ligne suivante. Aucun fichier
envoyé en entrée n'est modifié.
Jetons un œil à quelques exemples. Les premiers seront un peu étranges parce que
je les utiliserai pour montrer comment fonctionne Sed plus que pour effectuer
une manipulation quelconque. Cela dit, si vous utilisez Sed pour la première
fois, il est très important que vous compreniez ces exemples. Voici le premier
d'entre eux :
Exemple de code 1.1 : Exemple d'utilisation de Sed |
$ sed -e 'd' /etc/services
|
En tapant cette commande, vous n'obtiendrez absolument aucun message de sortie.
Bien, mais alors que se passe-t-il ? Dans cet exemple, nous exécutons Sed
avec une commande d'édition, d. Sed ouvre le fichier
/etc/services, lit une ligne dans son tampon d'édition, effectue
notre commande d'édition (« supprimer la ligne »), puis affiche le
tampon (qui est vide). Il répète la même étape pour chaque ligne du fichier.
Vous n'obtiendrez aucun message de sortie, puisque la commande d supprime
toutes les lignes du tampon d'édition !
Vous devez remarquer un certain nombre d'éléments dans cet exemple. Tout
d'abord, /etc/services n'a pas du tout été modifié. Cela est dû au
fait que Sed ne fait que lire le fichier spécifié dans la ligne de commande en
ne l'utilisant que comme flux d'entrée. Il n'essaye pas de modifier ce fichier.
Ensuite, vous remarquerez que Sed travaille en mode ligne par ligne. La commande
d n'indique pas simplement à Sed de supprimer toutes les données d'un
seul coup. À la place, Sed récupère l'une après l'autre les lignes de ce fichier
dans un tampon d'édition interne. Une fois qu'une ligne est mise dans le tampon
d'édition, Sed exécute la commande d sur ce tampon et renvoie en sortie
standard le résultat (dans notre exemple : rien, vu que le contenu est
supprimé). Plus tard, je vous montrerai comment utiliser des intervalles
d'adresses pour contrôler quelles lignes doivent être éditées par la commande.
Si aucune adresse n'est précisée, la commande sera appliquée à toutes les
lignes.
La troisième chose à remarquer est l'utilisation des apostrophes autour de la
commande d. Il est bon de prendre l'habitude d'utiliser des apostrophes
autour des commandes Sed pour que votre console Shell ne l'interprète pas.
Sed par l'exemple, deuxième exemple
Voici un exemple d'utilisation de Sed permettant de supprimer la première ligne
de /etc/services dans le flux de sortie :
Exemple de code 1.2 : Autre exemple de Sed |
$ sed -e '1d' /etc/services | more
|
Comme vous pouvez le voir, cette commande ressemble vraiment à la première
commande d, sauf que nous l'avons fait précéder d'un 1. Comme vous
l'aurez probablement deviné, le 1 indique une référence à la première
ligne. Contrairement au premier exemple, nous précédons le d d'une
adresse numérique optionnelle. En utilisant les adresses, vous pouvez indiquer à
Sed de n'effectuer les commandes que sur certaines lignes en particulier.
Intervalles d'adresses
Maintenant, intéressons-nous à spécifier un intervalle d'adresses. Dans
cet exemple, Sed va supprimer les lignes de 1 à 10 dans la sortie :
Exemple de code 1.3 : Spécifier un intervalle d'adresses |
$ sed -e '1,10d' /etc/services | more
|
Lorsque vous séparez deux adresses par une virgule, Sed va appliquer la commande
suivante à l'intervalle d'adresses compris entre la première et la seconde
adresse. Dans cet exemple, la commande d sera appliquée aux lignes de 1 à
10 incluses. Toutes les autres lignes seront ignorées.
Des adresses avec expressions régulières
Note :
N.d.T : Pour traduire « regular expression », nous utilisons ici
le terme « expression régulière », plus répandu que le terme plus
conventionnel « expression rationnelle ».
|
Il est maintenant temps de montrer des exemples utiles. Disons que vous
souhaitez voir le contenu du fichier /etc/services à l'exception
des commentaires. Comme vous le savez, vous pouvez placer des commentaires dans
votre fichier /etc/services en faisant commencer la ligne par un
dièse « # ». Pour éviter d'afficher les commentaires, nous allons
supprimer les lignes commençant par un dièse. Voici comment faire :
Exemple de code 1.4 : Supprimer les lignes commençant par un # |
$ sed -e '/^#/d' /etc/services | more
|
Essayez cet exemple et regardez ce qui se passe. Vous remarquerez que Sed
effectue sa tâche avec brio. Essayons de comprendre ce qui s'est passé.
Pour comprendre la commande « /^#/d », nous devons tout d'abord la
disséquer. Laissons de côté le d (nous utilisons la même commande de
suppression que précédemment). La partie nouvelle, ici, est /^#/ qui est
une adresse par expression régulière. Les adresses avec des expressions
régulières sont toujours encadrées par des /. Elles définissent un
modèle et la commande qui suit immédiatement l'expression régulière ne sera
appliquée que dans le cas où le texte vérifie les conditions spécifiées dans le
modèle indiqué.
Donc, /^#/ est une expression régulière. Mais que fait-elle ? À
l'évidence, c'est le bon moment pour se rafraîchir la mémoire à propos des
expressions régulières.
Petit topo sur les expressions régulières
Nous pouvons utiliser les expressions régulières pour indiquer un modèle que
nous souhaiterions rencontrer dans un texte. Si vous avez déjà utilisé le
caractère * dans une ligne de commande Shell, vous avez déjà utilisé
quelque chose qui est similaire (bien que pas identique) aux expressions
régulières. Voici les caractères spéciaux que vous pouvez utiliser dans les
expressions régulières :
| Caractère |
Description |
| ^ |
Indique un début de ligne. |
| $ |
Indique une fin de ligne. |
| . |
Indique n'importe quel caractère seul. |
| * |
Indique zéro ou plus occurrences du caractère précédent le *. |
| [ ] |
Indique l'occurrence d'un des caractères présents dans les [ ]. |
Le meilleur moyen de se faire la main avec les expressions régulières est de
voir quelques exemples. Tous ces exemples seront acceptés par Sed en tant
qu'adresses pouvant être placées à gauche d'une commande. En voici
quelques-uns :
| Expression régulière |
Description |
| /./ |
Récupère toutes les lignes contenant au moins un caractère. |
| /../ |
Récupère toutes les lignes contenant au moins deux caractères. |
| /^#/ |
Récupère toutes les lignes commençant par un #. |
| /^$/ |
Récupère toutes les lignes vides. |
| /}$/ |
Récupère toutes les lignes finissant par un }. |
| /} *$/ |
Récupère toutes les lignes finissant par un } suivi ou non d'espaces. |
| /[abc]/ |
Récupère toutes les lignes contenant un des caractères a, b ou c. |
| /^[abc]/ |
Récupère toutes les lignes commençant soit par un a, soit un b, soit un
c.
|
Je vous encourage d'essayer plusieurs de ces exemples. Prenez votre temps pour
vous familiariser avec les expressions régulières et pour essayer de nouvelles
expressions régulières faites maison. Vous pouvez utiliser une expression
régulière (ou regexp) de cette manière :
Exemple de code 1.5 : Méthode d'utilisation des regexp |
$ sed -e '/regexp/d' /chemin/d/acces/de/mon/fichier | more
|
Sed supprimera toutes les lignes respectant les règles de la regexp. Il est
cependant plus facile de s'habituer à l'usage des expressions régulières en
indiquant à Sed d'afficher les regexp qui sont vérifiées et de supprimer celles
qui ne correspondent pas, plutôt que l'inverse. Cela peut se faire avec la
commande suivante :
Exemple de code 1.6 : Afficher les expressions correspondant à une regexp |
$ sed -n -e '/regexp/p' /chemin/d/acces/de/mon/fichier | more
|
Remarquez la nouvelle option -n qui indique à Sed de n'afficher que les
modèles de texte demandés en commande. Vous noterez également que nous avons
remplacé la commande d par la commande p qui, comme vous l'aurez
probablement compris, demande explicitement à Sed d'afficher les lignes
reconnues par le modèle en question. Voilà. Maintenant, seules les lignes
reconnues par l'expression régulière seront affichées.
Plus loin avec les adresses
Jusqu'à maintenant, nous avons jeté un œil sur les adresses pour les lignes, les
intervalles d'adresses de lignes et les adresses par expression régulière, mais
il existe encore d'autres possibilités. On peut spécifier deux expressions
régulières séparées par une virgule et Sed reconnaîtra toutes les lignes depuis
la première ligne reconnue par la première expression régulière jusqu'à la
première ligne (incluse) reconnue par la seconde expression régulière. Par
exemple, la commande suivante affichera un bloc de texte commençant par une
ligne contenant « BEGIN » et terminant par une ligne contenant
« END » :
Exemple de code 1.7 : Affichage du bloc de texte souhaité |
$ sed -n -e '/BEGIN/,/END/p' /mon/fichier/texte | more
|
Si le mot « BEGIN » n'a pas été trouvé, rien ne sera affiché. De plus,
si « BEGIN » a été trouvé, mais que « END » n'a pas été
trouvé plus loin, toutes les lignes suivant le « BEGIN » seront
affichées. Cela est dû au fait que Sed est un éditeur de flux et donc il ne peut
pas deviner à l'avance si « END » sera ou non rencontré.
Exemple de traitement d'un code source en C
Si vous souhaitez n'afficher que la fonction main() d'un code source écrit en C,
vous pouvez écrire :
Exemple de code 1.8 : Affichage de la fonction main() d'un code en C |
$ sed -n -e '/main[[:space:]]*(/,/^}/p' fichiersource.c | more
|
Cette commande est composée de deux expressions régulières,
/main[[:space:]]*(/ et /^}/, suivies d'une commande, p. La
première expression régulière reconnaît la chaîne de caractère
« main » suivie de zéro ou plusieurs espaces ou tabulations, suivies
d'une parenthèse ouverte. Cela devrait reconnaître le début de votre fonction
main() écrite en ANSI C.
Dans ce cas particulier d'expression régulière, nous rencontrons la classe de
caractères « [[:space:]] ». Il s'agit d'un mot-clef spécial qui
indique à Sed de reconnaître soit une tabulation, soit une espace. Si vous le
souhaitez, au lieu d'écrire « [[:space:]] », vous pouvez écrire
« [ » suivi d'un caractère espace littéral, puis un Ctrl-V, une
tabulation littérale et enfin un « ] » (la commande Ctrl-V indique à
bash que vous souhaitez insérer une vraie tabulation plutôt qu'une complétion de
commande). Il est cependant plus lisible d'utiliser la classe de caractères
« [[:space:]] ».
Bon, passons maintenant à la seconde regexp. /^{/ reconnaîtra un
caractère « } » en début de ligne. Si votre code est correctement
formaté, il reconnaîtra alors le crochet fermant de votre fonction main(). Si
ce n'est pas le cas, cela n'affichera pas le code souhaité. C'est un point
important à noter lors de la reconnaissance de modèles.
La commande p fait ce qu'elle a toujours fait : indiquer de manière
explicite à Sed d'afficher les lignes souhaitées, en conjonction avec le mode
silencieux -n que nous utilisons. Essayez de lancer la commande sur un
code source écrit en C, Sed devrait alors afficher le bloc correspondant à la
fonction main(), en incluant les lignes « main() » et « } ».
Pour la suite
Maintenant que nous avons vu les bases, nous sommes prêts à passer aux deux
prochains articles. Si vous êtes avides de commandes Sed, soyez patient, elles
arrivent ! En attendant, vous pouvez jeter un œil sur les ressources
suivantes traitant de Sed et des expressions régulières.
2.
Ressources
Liens utiles
|