Gentoo Logo

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, 2e partie

Table des matières :

1.  Comment tirer plus de profit de l'éditeur de texte UNIX ?

Substitution !

Regardons l'une des commandes les plus pratiques de Sed, la commande de substitution. En l'utilisant, nous pouvons remplacer une chaîne de caractères ou une expression régulière par une autre chaîne de caractères. Voici un exemple de l'utilisation la plus fondamentale de cette commande :

Exemple de code 1.1 : L'utilisation la plus fondamentale de la commande de substitution

$ sed -e 's/foo/bar/' myfile.txt

Cette commande va afficher le contenu du fichier myfile.txt à l'écran avec la première occurrence de « foo » (si elle existe) rencontrée sur chaque ligne, remplacée par la chaîne de caractères « bar ». Notez-bien que j'ai dit la première occurrence de chaque ligne, bien que ce ne soit pas normalement ce que vous voulez. Normalement, quand je fais le remplacement d'une chaîne de caractères, je veux l'exécuter globalement. C'est à dire que je veux remplacer toutes les occurrences sur chaque ligne comme suit :

Exemple de code 1.2 : Remplacer toutes les occurences sur chaque ligne

$ sed -e 's/foo/bar/g' myfile.txt

L'option supplémentaire « g » après le dernier slash « / » indique à Sed de réaliser un remplacement global.

Voici quelques autres petites choses que vous devriez savoir au sujet de la commande de substitution s///. Tout d'abord, c'est une commande et seulement une commande : il n'y a pas de numéro de ligne spécifié dans les exemples précédents. Cela veut dire que la commande s/// peut aussi être utilisée avec des numéros de ligne pour préciser à quelles lignes elle doit s'appliquer, comme suit :

Exemple de code 1.3 : Préciser les lignes auxquelles la commande doit s'appliquer

$ sed -e '1,10s/enchantment/entrapment/g' myfile2.txt

L'exemple précédent entraîne le remplacement de toutes les occurrences du mot « enchantment » par le mot « entrapment » mais seulement de la première à la dixième ligne incluse.

Exemple de code 1.4 : Spécifier plus d'options

$ sed -e '/^$/,/^END/s/hills/mountains/g' myfile3.txt

Cette exemple remplace « hills » par « mountains » mais seulement sur les blocs de texte commençant par une ligne vide et se terminant par une ligne commençant par les trois caractères « END ».

Une autre chose de bien avec la commande s///, c'est que l'on peut remplacer le séparateur « / » par autre chose. Si nous réalisons un remplacement de chaîne de caractères et que l'expression régulière ou la chaîne de caractères de remplacement contient beaucoup de barres obliques (slashs), nous pouvons changer le séparateur en utilisant un caractère différent après le « s ». Par exemple, cela remplacera toutes les occurrences de /usr/local par /usr :

Exemple de code 1.5 : Remplacer toutes les occurences d'une chaîne de caractères par une autre

$ sed -e 's:/usr/local:/usr:g' mylist.txt

Note : Dans cet exemple, nous utilisons le caractère « : » comme séparateur. Si vous devez quand même utiliser le caractère de séparation dans l'expression régulière, ajoutez une barre oblique inverse (backslash « \ ») devant lui.

Avec des expressions régulières

Jusqu'à présent, nous avons seulement réalisé une simple substitution d'une chaîne de caractères. Bien que ce soit pratique, nous pouvons aussi rechercher une expression régulière. Par exemple, la commande suivante de Sed recherche une phrase commençant par « < », se terminant par « > » et contenant un nombre quelconque de caractères entre « < » et « > ». Cette phrase va être supprimée (remplacée par une chaîne de caractères vide) :

Exemple de code 1.6 : Supprimer une phrase spécifique

$ sed -e 's/<.*>//g' myfile.html

C'est un bon premier essai de script Sed qui retire des balises HTML à partir d'un fichier mais il ne marche pas bien à cause d'un caprice de l'expression régulière. La raison ? Quand Sed recherche une expression régulière sur une ligne, il recherche la correspondance la plus longue sur la ligne. Ceci n'est pas une correction à mon article précédent sur Sed car nous utilisions les commandes d et p qui supprimaient de toute façon la ligne entière. Mais quand nous utilisons la commande s///, cela est très différent parce que la partie entière que l'expression régulière trouve est remplacée par la chaîne de caractères de remplacement ou, comme dans le cas précédent, est supprimée. Cela signifie que l'exemple précédent transforme la ligne suivante :

Exemple de code 1.7 : Exemple de code HTML

<b>C'est</b> ce que <b>nous</b> voulons.

En :

Exemple de code 1.8 : Effet non désiré

voulons.

Au lieu de ça, voici ce que nous souhaitions :

Exemple de code 1.9 : Effet désiré

C'est ce que nous voulons.

Heureusement, il y a un moyen facile de corriger ça. Au lieu de taper une expression régulière qui dit « un caractère "<" suivi par un nombre quelconque de caractères et se terminant par un caractère ">" », nous avons juste à taper une expression régulière qui dit « un caractère "<" suivi par un nombre quelconque de caractères n'étant pas ">" et se terminant par un caractère ">" ». Cela a pour effet de rechercher la plus petite correspondance plutôt que la plus longue. Voici à quoi ressemble la nouvelle commande :

Exemple de code 1.10 :

$ sed -e 's/<[^>]*>//g' myfile.html

Dans l'exemple précédent, le « [^>] » correspond à un caractère n'étant pas « > » et le « * » qui le suit complète cette expression signifiant « zéro ou plus de zéro caractère n'étant pas ">" ». Testez cette commande sur quelques fichiers HTML puis examinez les résultats obtenus.

Plus de caractères de correspondance

La syntaxe de l'expression régulière « [ ] » a quelques options supplémentaires. Pour spécifier une série de caractères, vous pouvez utiliser un « - » tant qu'il n'est pas en première ou dernière position, comme ceci :

Exemple de code 1.11 : Spécifier une série de caractères

'[a-x]*'

Cela recherche zéro caractère ou plus, tant que ceux-ci sont « a », « b », « c »... « v », « w » et « x ». De plus, la classe de caractères « [:space:] » est disponible pour rechercher une espace. Voici une liste assez complète des classes de caractères disponibles :

Classe de caractères Description
[:alnum:] Alphanumérique [a-z A-Z 0-9]
[:alpha:] Alphabétique [a-z A-Z]
[:blank:] Espace ou tabulation
[:cntrl:] Tout caractère de contrôle
[:digit:] Chiffre [0-9]
[:graph:] Tout caractère visible (sauf le caractère espace)
[:lower:] Minuscule [a-z]
[:print:] Un caractère qui n'est pas un caractère de contrôle.
[:punct:] Caractère de ponctuation
[:space:] Espace
[:upper:] Majuscule [A-Z]
[:xdigit:] Caractère hexadécimal [0-9 a-f A-F]

Il est avantageux d'utiliser des classes de caractères lorsque cela est possible car ils s'adaptent mieux dans les environnements non-anglophones (par exemple, en incluant les caractères accentués lorsque cela est nécessaire).

Commandes avancées pour la substitution de chaînes de caractères

Nous avons vu comment réaliser des substitutions simples et même relativement complexes mais Sed peut faire bien plus. Nous pouvons réellement nous référer à des parties ou à l'expression régulière entière trouvée et utiliser ces parties pour construire la chaîne de caractères de remplacement. Par exemple, disons que vous répondez à un message. L'exemple suivant va préfixer chaque ligne avec la phrase « ralph a dit » :

Exemple de code 1.12 : Préfixer chaque ligne avec une chaîne de caractères

$ sed -e 's/.*/ralph a dit : &/' origmsg.txt

Le résultat affiché ressemblera à quelque chose comme ça :

Exemple de code 1.13 : Résultat affiché par la commande

ralph a dit : Hiya Jim,
ralph a dit : 
ralph a dit : I sure like this sed stuff!
ralph a dit :

Dans cet exemple, nous utilisons le caractère « & » dans la chaîne de caractères de remplacement, ce qui indique à Sed d'insérer l'expression régulière entière rencontrée. Donc, tout ce qui correspond à « .* » (le groupe le plus large composé de zéro ou plus de caractères sur la ligne, autrement dit la ligne entière) peu être inséré où l'on veut dans la chaîne de caractères de remplacement, même plusieurs fois. C'est génial mais Sed est encore plus puissant.

Ces magnifiques parenthèses backslashées

Encore mieux que « & », la commande s/// nous permet de définir des zones dans notre expression régulière et nous pourrons nous référer à ces zones spécifiques dans notre chaîne de remplacement. Par exemple, disons que nous avons un fichier qui contient le texte suivant :

Exemple de code 1.14 : Exemple de texte

foo bar oni
eeny meeny miny
larry curly moe
jimmy the weasel

Maintenant, disons que nous voulons écrire un script Sed qui remplace « eeny meeny miny » par « Victor eeny-meeny Von miny », etc. Pour faire ça, tout d'abord nous devons écrire une expression régulière qui doit correspondre aux trois chaînes de caractères séparées par des espaces :

Exemple de code 1.15 : Expression régulière correspondante

'.* .* .*'

Voilà. Maintenant, nous allons définir les zones en insérant des parenthèses backslashées autour de chaque zone qui nous intéresse :

Exemple de code 1.16 : Définir des zones

'\(.*\) \(.*\) \(.*\)'

Cette expression régulière travaille de la même façon que la première, exceptée qu'elle définit trois zones logiques auxquelles nous pouvons nous référer dans notre chaîne de caractères de remplacement. Voici le script final :

Exemple de code 1.17 : Script final

$ sed -e 's/\(.*\) \(.*\) \(.*\)/Victor \1-\2 Von \3/' myfile.txt

Comme vous pouvez le voir, nous nous référons à chaque zone délimitée par des parenthèses en tapant « \x » où x est le numéro de la région, démarrant à un. Le résultat affiché est le suivant :

Exemple de code 1.18 : Résultat affiché par la commande précédente

Victor foo-bar Von oni
Victor eeny-meeny Von miny
Victor larry-curly Von moe
Victor jimmy-the Von weasel

Au fur et à mesure que vous vous familiariserez avec Sed, vous serez capable de réaliser des traitements de textes assez puissants avec un minimum d'efforts. Vous pouvez réfléchir à la façon dont vous auriez traité ce problème en utilisant votre langage de script favori : pouvez-vous facilement trouver une solution tenant sur une seule ligne ?

Utiliser plusieurs commandes

Comme nous commençons à créer des scripts Sed plus complexes, nous avons besoin d'être capables d'entrer plus d'une commande. Il y a plusieurs manières de procéder. Tout d'abord, nous pouvons utiliser des points-virgules entre les commandes. Par exemple, cette série de commandes utilise la commande « = » qui indique à Sed de n'afficher que le numéro de ligne puis la commande « p » qui indique à Sed d'afficher la ligne (puisque nous sommes dans le mode « -n » :

Exemple de code 1.19 : Première méthode, les points-virgules

$ sed -n -e '=;p' myfile.txt

Même si deux commandes ou plus sont spécifiées, chaque commande est appliquée (dans l'ordre) à chaque ligne du fichier. Dans l'exemple précédent, tout d'abord la commande « = » est appliqué à la ligne 1 puis la commande p est appliquée. Puis, Sed traite la ligne 2 et répète le processus. Bien que l'utilisation du point-virgule soit pratique, il y a des situations où cela ne fonctionnera pas. Une autre solution est d'employer deux fois l'option « -e » pour spécifier séparément les deux commandes :

Exemple de code 1.20 : Deuxième méthode, plusieurs « -e »

$ sed -n -e '=' -e 'p' myfile.txt

Cependant, quand nous verrons les commandes plus complexes d'ajout et d'insertion, même plusieurs options « -e » ne nous aideront pas. Pour des scripts complexes de plusieurs lignes, la meilleure façon est de saisir vos commandes dans un fichier séparé. Puis référencez ce fichier de script avec l'option « -f » :

Exemple de code 1.21 : Troisième méthode, un fichier externe contenant les commandes

$ sed -n -f mycommands.sed myfile.txt

Cette méthode, bien que discutablement moins pratique, fonctionnera toujours.

Utiliser plusieurs commandes sur un groupe de lignes

Parfois, vous pourrez vouloir spécifier plusieurs commandes qui s'appliqueront à une simple ligne. Ceci devient particulièrement pratique quand vous réalisez beaucoup de substituions s/// pour transformer des mots ou la syntaxe dans le fichier source. Pour réaliser plusieurs commandes par ligne, entrez vos commandes Sed dans un fichier et utilisez les caractères « { } » pour grouper les commandes comme suit :

Exemple de code 1.22 : Réaliser plusieurs commandes par ligne

1,20{
        s/[Ll]inux/GNU\/Linux/g
        s/samba/Samba/g
        s/posix/POSIX/g
}

L'exemple précédent applique trois commandes de substitutions de la ligne 1 à la ligne 20 incluse. Vous pouvez aussi utiliser une expression régulière pour spécifier les numéros de ligne ou une combinaison des deux :

Exemple de code 1.23 : Combinaison des deux méthodes

1,/^END/{
        s/[Ll]inux/GNU\/Linux/g 
        s/samba/Samba/g 
        s/posix/POSIX/g 
       p
}

Cet exemple applique les commandes entre accolades « { } » de la ligne 1 (première ligne) à la ligne commençant par les lettres « END » ou la fin du fichier si « END » n'est pas trouvé dans le fichier source.

Ajouter, insérer et modifier une ligne

Maintenons que nous savons écrire des scripts Sed dans des fichiers séparés, nous pouvons profiter des commandes permettant d'ajouter, insérer et modifier les lignes. Ces commandes insèrent une ligne après la ligne courante, insèrent une ligne avant la ligne courante ou remplacent la ligne courante.

Exemple de code 1.24 : Utiliser la commande d'insertion de ligne

i\
Cette ligne sera insérée avant chaque ligne

Si vous ne précisez pas les numéros de ligne auxquelles doit s'appliquer ce script, il sera appliqué à chaque ligne et produira l'affichage de quelque chose ressemblant à ça :

Exemple de code 1.25 : Résultat affiché par la commande précédente

Cette ligne sera insérée avant chaque ligne
ligne 1
Cette ligne sera insérée avant chaque ligne
ligne 2
Cette ligne sera insérée avant chaque ligne
ligne 3
Cette ligne sera insérée avant chaque ligne
ligne 4

Si vous souhaitez insérer plusieurs lignes avant la ligne actuelle, vous pouvez les ajouter en les terminant par un backslash « \ » comme ceci :

Exemple de code 1.26 : Insérer plusieurs lignes avant la ligne actuelle

i\
insère cette ligne\
et celle-ci\
et celle-ci\
et, euh, celle-ci aussi.

La commande d'ajout fonctionne de la même façon mais elle insère une ou plusieurs lignes après la ligne courante. Elle est utilisée comme suit :

Exemple de code 1.27 : Ajouter des lignes après la ligne courante

a\
Ajoute cette ligne après chaque ligne. Merci ! :)

D'autre part, la commande de modification de ligne remplace la ligne courante et est utilisée comme suit :

Parce que les commandes d'ajout, d'insertion et de modification de ligne ont besoin d'être saisies sur plusieurs lignes, vous devriez les taper dans un fichier texte et indiquer ce fichier texte contenant le script en utilisant l'option « -f ». Utiliser les autres méthodes pour passer ces commandes à Sed entraînera des problèmes.

La prochaine fois

La prochaine fois, dans le dernier article de cette série sur Sed, je vous montrerai beaucoup d'exemples excellents utilisant Sed dans le monde réel pour beaucoup de types de tâches différentes. Non seulement je vous expliquerai ce que les scripts font mais aussi pourquoi ils font ce qu'ils font. Une fois que ce sera fait, vous aurez des idées supplémentaires excellentes pour utiliser Sed dans des projets variés.

2.  Ressources

Liens utiles



Imprimer

Dernière mise à jour le 9 octobre 2005

Une version originale plus récente datée du 9 octobre 2005 existe.

Résumé : Sed est un petit éditeur de textes très puissant. Dans cet article, le deuxième de la série, Daniel vous explique comment utiliser Sed pour réaliser des substitutions de chaînes de caractères, créer des scripts Sed plus avancés et utiliser Sed pour ajouter, insérer et modifier les lignes de commandes.

Daniel Robbins
Auteur

Christophe Lefebvre
Traducteur

Donate to support our development efforts.

Copyright 2001-2014 Gentoo Foundation, Inc. Questions, Comments? Contact us.