Sed par l'exemple, Première partie Daniel Robbins Łukasz Damentko Clément Varaldi Dans cette série d'articles, Daniel Robbins vous montrera comment utiliser sed, un très puissant (mais souvent méconnu) éditeur UNIX de flux. Sed est l'outil idéal pour l'édition de fichiers en batch ou pour créer des scripts Shell pour modifier des fichiers existants de manière efficace. 1.0 2005-07-15 Prise en main de sed, puissant éditeur UNIX
Le choix de l'éditeur La version originale de cet article a été publiée par les développeurs IBM, 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 de nombreuses améliorations proposées par l'équipe de documentation de Gentoo Linux.

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, 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 quelles taches d'administration liées à la programmation ou à l'administration UNIX.

Si les éditeurs interactifs sont puissants, ils ont des l imitatons. 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 répétitive et longue s'il en est. Mais il existe un meilleur moyen.

Utiliser sed

Ce serait bien si nous pouvions automatiser le processus d'édition des fichiers, et ainsi pouvoir éditer en ligne de commande, voire même écrit 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, et cette solution s'appelle sed.

sed est un éditeur de flux léger inclu 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, ce qui lui permet d'é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 sur un fichier sauvegardé sur disque 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 existante se trouve être GNU sed, actuellement dans sa version 3.02. Toutes les distributions Linux ont GNU sed, ou du moins devraient. 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 les récentes solutions propriétaires de sed ont, comme par exemple une limite à la longueur des lignes (GNU sed gère avec aisance les lignes de toute taille).

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é 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 trouver quelques minutes plus tard que la version de sed la plus récente est 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 autant d'opérations d'éditions précisées par l'utilisateur que nécessaire (des « commandes ») en options à la commande. Sed est un programme en ligne de commande. Ainsi, les commandes sont effectuées ligne après ligne, dans l'ordre. Il écrit le résultat sur la sortie standard (stdout). Aucun fichier mis en entrée n'est modifié.

Jetons un œil à quelques exemples. Les quelques premiers exemples 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 :

$ 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 seulement à 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 rangs d'adresse 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 simples guillemets autour de la commande d. Il est bon de prendre l'habitude d'utiliser des guillemets simples pour les 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 :

$ 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 sed que sur certaines lignes en particulier.

Rangs d'adresse

Maintenant jetons un oeil sur comment spécifier un rang d'adresse. Dans cet exemple, sed va supprimer les lignes de 1 à 10 dans la sortie :

$ sed -e '1,10d' /etc/services | more

Lorsque vous séparez deux adresses par une virgule, sed va appliquer la commande suivante au rang d'adresse compris entre la première adresse et la seconde. Dans cet exemple, la commande d va s'appliquer aux lignes de 1 à 10 incluses. Toutes les autres lignes seront ignorées.

Des adresses avec expressions régulières

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 « # ». Pour éviter d'afficher les commendaires nous allons supprimer les lignes commençant par un « # ». Voici comment faire :

$ sed -e '/^#/d' /etc/services | more

Essayez cet exemple et regardez ce qui se passe. Vous remarquerez que sed effectue sa tache 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 indioquer 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 :

^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'au moins l'un des caractères présents dans [ ]
Caractère Description

Le meilleur moyen de se faire la main avec les expressions régulières est de voir quelques exemples. Tous ces exemples seront des compatibles avec sed en tant qu'adresses pouvant être placées avant une commande. En voici quelques-un :

/./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 blanches/}^/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 au moins l'un des caractères a, b ou c/^[abc]/Récupère toutes les lignes commençant soit pas un a, soit un b, soit un c
Expression régulière Description

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 :

$ 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 :

$ 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 addresses

Jusqu'à maintenant nous avons jeté un oeil sur les adresses pour les lignes, les rangs d'adresses de lignes, et les adresses par expressions régulières. 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 » :

$ 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 :

$ 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 recontrons 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 un espace. Si vous le souhaitez, au lieu d'écrire « [[:space:]] » vous pouvez écrire « [ » suivi d'un 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 formatté, 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ée, 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êt à passer aux deux prochains articles. Si vous êtes avides de commandes sed, soyez patient, elles arrivent ! En attendant, vous pouvez jeter un oeil sur les ressources suivantes traitant de sed et des expressions régulières.

Ressources
Liens utiles
  • Lisez les autres articles que Daniel a écrit dans le cadre du developerWorks de IBM : Sed par l'exemple, Deuxième partie et Troisième partie.
  • Lisez l'excellente FAQ pour sed FAQ (en anglais) de Eric Pement.
  • Vous trouverez les sources de sed 3.02 sur ftp://ftp.gnu.org/pub/gnu/sed.
  • Vous trouverez l'excellente nouvelle version de sed 3.02.80 sur http://alpha.gnu.org.
  • Eric Pement met également à disposition de tous une bonne liste de commandes sed en une ligne que tout aspirant au poste de gourou de sed doit avoir lu.
  • Si vous aimez les livres à l'ancienne mode, le livre O'Reilly's sed & awk, 2nd Edition (en anglais) sera un excellent choix.
  • Lisez l'article de David Mertz sur la reconnaissance de texte en Python (en anglais) sur le site du developerWorks.
  • Poursuivez votre exploration sur comment utiliser les expressions régulières (en anglais) pour trouver et modifier des modèles de texte avec ce guide gratuit et exclusif du developerWorks.
  • Lisez ce document sur les expressions régulières (en anglais) sur le site Python.org.
  • Référez-vous enfin à cet aperçu sur les expressions régulières (en anglais) de l'Université du Kentucky.