mercredi 15 décembre 2010

Filtre Sed - Présentation des fonctionnalités

Le programme informatique sed (Stream Editor) est un éditeur de flux textuel très puissant.
La plupart des personnes utilisent sed pour ses fonctionnalités de substitutions de chaînes de caractères. Il est possible, par exemple, grâce au filtre sed de rechercher du texte dans un fichier et de modifier ce dernier. La puissance du filtre sed vient également du fait qu'il est possible d'utiliser des expressions régulières.

Son principe de fonctionnement est le suivant:
Sed lit en entrée les données ligne par ligne (en provenance d'un fichier ou d'ailleur) et modifie ces dernières selon des règles spécifiques entrées par l'utilisateur.

On peut dire que le filtre sed est une sorte d'éditeur de texte non interactif ou editeur de texte en ligne de commande.

I. Syntaxe d'utilisation

La commande sed contient une ou plusieurs commandes d'éditions et éventuellement des options.
sed [OPTIONS] 'commande d'édition' [fichier...]

Le filtre Sed met à dispositions diverses options et commandes d'éditions. Nous verrons dans un premier temps (dans le sous chapitre I.a.) quelles sont les différentes options disponibles, puis dans un deuxième temps (dans le sous chapitre I.b.), nous aborderons les commandes d'éditions.

I.a. Options :

Je ne vous parlerai ici que des options sed les plus couramment utilisées. Vous pourrez éventuellement taper la commande man sed pour avoir une liste d'options plus complète.

-e commande
L'option -e est très utile car elle permet d'utiliser plusieurs commandes d'édition à la suite.
Exemple : sed -e 'commande' -e 'commande'


-f Fichier_Script
Cette option permet d'ajouter des commandes d'édition se trouvant dans un fichier script. Faire un fichier script est très simple, il suffit de remplir ce dernier avec des commandes d’éditions (chaque ligne doit comporter une commande d'édition différente).


-i[SUFFIXE]
Par défaut sed ne modifie pas directement le fichier qui est fournit en paramètre mais affiche le résultat du traitement sur la sortie standard (stdout). Grâce à cette option sed modifiera directement le fichier fournit en paramètre. On éventuellement mettre un suffixe pour effectuer une sauvegarde du fichier fournit (Exemple de suffixe: -i.bak)

I.b. Commandes d'éditions sed:

Pour éditer le texte sed met a disposition plusieurs commandes d'éditions permettant de spécifier les règles de modification souhaitées. Ces dernières ont une syntaxe d'utilisation particulière que je vais tenter de vous décrire.

La syntaxe d'utilisation des commandes d'éditions sed est la suivante :

[addresse[,addresse]]commande d'édition[arguments]

Comme vous pouvez l'observer, une commande d'édition sed peut être préfixé par une ou deux adresses.

Les adresses :
Les adresses correspondent à des lignes du texte. Il est possible de spécifier les numéros de lignes, par exemple les adresses 5,7 indiqueront à la commande sed d'agir sur les lignes 5 à 7. On peut également utiliser des expressions régulières, par exemple l'adresse /motif/ indiquera à sed de traiter les lignes correspondantes à l'expression régulière motif. Chaque ligne contenant la chaîne de caractères motif sera alors traitée. On peut deux la même façon utiliser deux expressions régulières, par exemple /motif1/,/motif2/ correspond à un domaine de lignes compris entre motif1 et motif2. Nous verrons plus bas comment utiliser les expression régulières.


Maintenant nous allons aborder les commandes d'éditions sed disponibles pour editer le texte. Ces dernières peuvent supporter parfois qu'une seule adresse maximale. D'autres peuvent en supporter deux.

Les commandes d'éditions sed pouvant supporter une adresse :
[adresse]i
Cette commande d'édition sed permet d’insérer du texte avant la ligne correspondante à l'adresse. Si aucune adresse n'est spécifiée le texte sera inséré au début.
[adresse]a Ajoute du texte après la ligne.
q Afficher les n premières lignes.

II. Insérer et ajouter du texte

Vous pouvez utiliser la commande i pour insérer du texte avant une ligne et a pour ajouter du texte après une ligne.


Ajouter Bonjour monsieur après la ligne 5
sed '5a\Bonjour monsieur\' fichier.txt

Insérer Bonjour monsieur avant la ligne 5
sed '5i\Bonjour monsieur\' fichier.txt

III. Substitution

Sed permet de rechercher et remplacer des mots ou des parties de texte, on appelle cela: substituer des chaînes de caractères.

Par exemple pour substituer une occurrence par une autre:
Remplacer romain par julien
sed -e 's/romain/julien/' fichier.txt

III.a. Utiliser l'option global g
Sed traite le flux ligne par ligne. Attention, sans l'option g sed ne traitera que la première occurrence trouvé sur la ligne en cours de traitement, c'est à dire que si sur une même ligne, la chaîne de caractères recherchée apparaît plusieurs fois, seulement la première occurrence sera traitée. L'option g permet de traiter toutes les occurrences.
Utilisation de l'option g (global)
sed -e 's/toto/titi/g' fichier.txt

III.b. Utiliser l'option de négation !
Afin d'inverser la fonction sed utilisée, il est possible d'utiliser l'opérateur ! dit de négation.

Voici un exemple:
Remplacer tonton par tati sauf à la ligne 5
sed '5!s/tonton/tati/g' fichier.txt

III.c. Agir uniquement sur certaines lignes du fichier
Il possible de dire à sed de ne traiter qu'une partie du fichier texte, pour cela on utiliser une plage d'adresse correspondant aux lignes qu'on souhaite traiter.

Voici ci dessous un exemple:
Remplacer tonton par tati uniquement entre les lignes 5 et 12
sed '5,12s/tonton/tati/g' fichier.txt

III.d. Sélectionner les occurrences
Si jamais il y a plusieurs occurrences d'une même chaîne sur une même ligne, il est possible d'indiquer à sed laquelle on souhaite traiter.

Exemple:
Remplacer seulement la deuxième occurrence du mot téléphone par le mot fax
sed 's/telephone/fax/2'

IV. Afficher du texte

L'option p qui a pour signification print permet de sélectionner et d'afficher du texte.
Afficher les lignes 18 à 25
sed -n '18,25p' fichier.txt

Il est possible avec sed de sélectionner un paragraphe.
Afficher le paragraphe qui commence par la ligne contenant la chaîne de caractère prendre la voiture et qui termine par la ligne contenant la chaîne arriver le soir
sed -n '/prendre la voiture/,/arriver le soir/p' monfichier

V. Effacer du texte

Sed permet grâce à la fonction d (delete) d’effacer des chaînes de caractères.
Par exemple, si vous souhaitez éffacer les lignes 18 à 25 d'un fichier, vous pouvez taper la commande suivante:
sed '18,25d' fichier.txt

Si maintenant, vous souhaitez effacer tout sauf les trois premières lignes d'un fichier, vous pouvez taper la commande suivante:
sed '1,3!d' fichier.txt

VI. Les méta-caractères

Les métacaractères sont des caractères typographiques spéciaux qui permettent de créer des expressions rationnelles; ces dernières sont utiles pour rechercher des chaînes de caractères répondant à certain critères.
Metacaractère Description
. Désigne un seul caractère quelconque excepté le caractère '\n' (nouvelle ligne).

Par exemple:
tot. correspond à tota, totb, totc, totd, tote etc...
^ Indique le début de la ligne

Par exemple:
^root identifie une ligne commençant par root
$ Indique la fin d'une ligne

Par exemple:
mécanisme$ identifie une ligne finissant par mécanisme
[ ]Correspond à n'importe quel caractères cités entre les crochets

Exemple 1 :
[tT]toto correspond aux chaînes de caractères toto et Toto

Exemple 2 :
[a-z] correspond à l'intervalle de caractères de a jusqu'à z

Exemple 3 :
[4-9] correspondant à l'intervalle de caractères de 4 à 9 c'est à dire 4,5,6,7,8,9

Exemple 4 :
1[4-9]0 correspondant à 140,150,160,170,180,190

VI.a. Exemples d'utilisation des métacaractères avec la commande Sed:

VI.a.1. Exemple d'utilisation du métacaractère .

Remplacer ce qui commence par tot et qui fait 4 caractères par toto
sed -e "s/tot./toto/g"
Le métacaractére . représente un caractère quelconque.

VI.a.2. Exemple d'utilisation du metacaractère ^

Effacer les lignes débutant par ^root
sed -e "/^root/d"

Modifier les lignes qui débutent par root en substituant ce dernier par user
sed -e "s/^root/user/"

VI.a.3. Exemple d'utilisation du metacaractère $

Supprimer les lignes finissant par la chaîne de caractères toto
sed "/toto$/d"

Supprimer les lignes vides
sed -e "/^$/d"

Modifier les lignes terminant par ; par le caractère .
sed -e "s/$;/\./"

VI.a.4. Exemple d'utilisation des metacaractères []

Remplacer les chaînes qui commencent par toto et qui finissent par un chiffre entre 0 et 9 par la chaîne tata
sed -e "s/toto[0-9]/tata/g"

Supprimer les caractères a, b ou c
sed -e "s/[abc]//g"

VII. Les quantificateurs

Les quantificateurs se place après un caractères et permettent d'exprimer une valeur de répétition ou de nullité.
Quantificateurs Description
* Aucun ou plusieurs caractère qui le précède

Exemple :
toto* correspond à tot, toto, totoo, totooo etc...

Remarque:
.*Correspond à zéro ou plusieurs caractères quelconques
? Zéro ou une occurrence du caractère qui le précède

Exemple :
toto? correspond à tot ou toto

+ Un ou plusieurs caractères qui le précède

Exemple :
toto+ correspond à toto, toto, totoo, totooo etc...


VII.a. Exemples d'utilisation des quantificateurs avec Sed:

VII.a.1. Exemple d'utilisation du quantificateur *

Remplacer tout ce qui commence par tot et qui est suivi du caractère o zéro ou plusieurs fois (c'est à dire: tot, toto, totoo, totooo, totoooo...) par la chaîne baba
sed -e "s/toto*/toto/g"

Supprimer les chaînes de caractères qui commencent par toto, qui contiennent n'importe quels caractères et finissent par baba
sed -e "/^toto.*baba$/d"

VII.a.2. Exemple d'utilisation du quantificateur ?

Remplacer tat ou tati par toto
sed -e "s/tati?/toto/g"

VII.a.2. Exemple d'utilisation du quantificateur +

Remplacer ce qui correspond à tata, tataa, tataaaa etc... par le mot toto
sed -e "s/tata+/toto/g"

Liens internes


Liens externes


18 commentaires:

  1. Ce commentaire a été supprimé par l'auteur.

    RépondreSupprimer
  2. Bonjour oumina el hassane,

    Je vais essayer de t'expliquer ce que fait la commande sed que tu as écrite:

    Cette commande va ajouter une ligne dans le fichier /etc/squid3/squid.conf

    La ligne qui s'ajoute automatiquement est la suivante:
    visible_hostname "Nom d'hôte de votre ordinateur"

    En tapant:
    echo $HOSTNAME
    vous pouvez voir le nom d’hôte de votre machine.

    Cette ligne va s'ajouter dans le fichier "squid.conf" juste en dessous de la ligne suivante déjà présente:
    # visible_hostname

    Les étapes Sed se décomposent de la manière suivante:


    ETAPE 1:
    --------
    On peut voir l'utilisation de l'option "-i" (/bin/sed -i) dans ta commande, cela signifie que le fichier est directement modifié.


    ETAPE 2:
    --------
    Ta commande sed peut être décomposée (grâce aux crochets) en deux parties distinctes:
    ADRESSE{COMMANDES;}
    C'est la première chose importante à remarquer.
    Les crochets utilisés dans ta commande Sed permettent de délimités ces deux parties.


    ETAPE 3:
    --------
    La première partie de la commande qui se trouve avant la partie entre crochets "{ }" est la suivante:
    /TAG: visible_hostname/,/^#[ ]*visible_hostname/

    Cela correspond a une adresse;
    Une adresse peut être décomposée en deux autres parties distinctes:
    /LIGNE1,/LIGNE2/

    Sed va repérer et traiter uniquement la partie textuelle qui se trouve entre les lignes 1 et 2.


    ETAPE 4:
    --------
    La ligne 1 de ta commande est la ligne qui contient la chaîne de caractères suivante:
    TAG: visible_hostname

    La ligne 2 correspond à l'expression rationnelle suivante:
    ^#[ ]*visible_hostname


    ^# correspond à une chaîne de caractères qui commence par #

    [ ]* correspond à zéro, un ou plusieurs caractères espaces.

    Donc, pour la ligne 2 qui est une expression rationnelle, Sed va rechercher une ligne de texte :

    - qui commence par le caractère #
    - et qui contient éventuellement un, zéro ou plusieurs caractères espaces.


    ETAPE 5:
    --------
    Maintenant que nous avons délimité la partie dans laquelle le traitement allait être effectuer nous allons nous pencher sur la commande.

    La commande est la partie qui se trouve entre les crochets, c'est à dire :
    {/#[ ]*visible_hostname/a\\
    visible_hostname $HOSTNAME;}


    ETAPE 6:
    --------

    /#[ ]*visible_hostname/a

    se décompose en en deux parties:
    /ADRESSE/fonction

    #[ ]*visible_hostname
    Demande a sed de traiter la chaîne de caractères qui commence par le caractère #, qui contient éventuellement des caractères espaces et qui finie par la chaîne de caractères visible_hostname

    /#[ ]*visible_hostname/a
    on peut voir l'utilisation de la fonction "a" à la fin.
    Cela signifie que tu texte va être ajoute après la ligne qui correspond à l'expression rationnelle suivante:
    #[ ]*visible_hostname

    ETAPE 7:
    --------
    visible_hostname $HOSTNAME;

    Pour finir, le texte ajouter est le suivant:
    visible_hostname $HOSTNAME

    $HOSTNAME correspond à la variable d'environnement.
    Pour connaitre son contenu il suffit de taper :
    echo $HOSTNAME


    CONCLUSION:
    -----------
    Ce script sed initialise la variable squid visible_hostname avec la valeur $HOSTNAME de votre environnement Shell.

    RépondreSupprimer
  3. voila j'ai bien saisi , merci bien romain merci encore mille fois maintenant je suis :-)

    RépondreSupprimer
  4. Bonjour, j'aurai voulu savoir comment passer un numéro de ligne en paramètre dans sed.
    Je m'explique :
    J'ai un script qui récupère un numéro de ligne dans une variable $TOTO et je voudrai supprimer cette ligne avec sed mais je n'y arrive pas. Par contre si j'utilise un numéro de ligne directement cela fonctionne.

    La ligne qui ne marche pas
    sed -i {$TOTO}d test.conf

    La ligne qui marche
    sed -i 97d test.conf

    J'ai fait plusieurs essais avec des \ des quotes mais je n'ai pas trouvé...(ouais sur ce coup là je suis mauvais)

    Peux-tu éclairer ma chandelle ?

    RépondreSupprimer
  5. Bonjour John,

    Au lieu de la commande: sed -i {$TOTO}d test.conf

    essayes plutot ceci:
    sed -i ${TOTO}d test.conf
    ou
    sed -i "${TOTO}d" test.conf

    Tiens moi au courant :)

    RépondreSupprimer
  6. Bonjour,
    J'ai un souci je voudrai récupérer dans un fichier texte une valeur comme ceci par exemple "12,45" et la transformer en "12.45" en gros "xx,xx" => "xx.xx"
    bref j'ai essayé cette ligne de comande

    /bin/sed -i -e "\"[1-9]{3},[0-9]{2}\"/\"[1-9]{3}\.[0-9]{2}\"" monfchier

    Je me suis rendu compte que la variable de substitution ne peux pas être une expression régulière dans ce que je me demande est ce qu'on sur linux on peut trouvé un equivalent de preg_match() en php pour récupéré la valeur et la modifier.

    Merci d'avance.
    Débutant sur linux
    Mr Anas

    RépondreSupprimer
  7. Il faut pour cela utiliser les variables :

    sed -ie "s#\(\"[0-9]*\),\([0-9]*\"\)#\1.\2#g" fichier


    il faut mettre une expression entre parentheses comme cela \( EXPRESSION1 \) puis \( EXPRESSION2 \) et recuperer ce que tu as mis entre parentheses grace à \1 puis \2 ....etc

    RépondreSupprimer
  8. Excellent tutoriel, qui plus est en français, je suis un pro sed maintenant :p merci pour ta contribution.

    RépondreSupprimer
  9. Bonjour à tous, tout d'abord, excellent tuto ! j'ai une petite question : je dispose d'un fichier qui contient le type d'information suivante :

    produit:98:2450
    Cout:19421 21959Necessaire pour le produit 99:2538

    Je souhaite conserver uniquement les valeurs 98 et 99:2538, qui peuvent etre des valeurs avec plusieurs chiffres.

    j'arrive à créer une regex qui correspond à ces valeurs : [0-9]+:[0-9]+$ ; mais je n'arrive pas à garder que ça...
    une petite aide?

    RépondreSupprimer
  10. Bonjour à tous, effectivement ce tutoriel est bien complet, et m'a pas mal déjà aidé; vu qu'il ya des experts, je me permet de poser ma question ici :

    je souhaiterai enlever chaque lignes dont le caractère (exemple A) est répété plus de 2 fois dans la totalité de la ligne et non, pas seulement 2 fois à la suite (même si quelque part cela revient au memme ... j'ai d'ailleur cette commande qui le fait : sed '/\([A-Z]\|[A-Z]\1\{2,\}/d' elle supprime uniquement 2 fois le même caractère à la suite compris entre A à Z)

    Donc se serait pour ma demande l'exemple suivant :
    ABCD => conservé
    ABCA => supprimé il ya + de 2 fois le A dans la ligne
    AABC => supprimé exemple de ma commande citée ci-dessus (2 fois de suite le A)
    BCDAD => supprimé il ya + de 2 fois le D dans la ligne
    BCACCC => supprimé il ya plus de 2 fois le C dans la ligne

    Voilà, c'est pas simple mais merci d'avance pour une réponse.

    RépondreSupprimer
    Réponses
    1. Bonjour,
      Élimination des lignes contenant au moins 2 fois le même caractère
      je propose en test :
      echo -e "ABCD\nABCA\nAABC\nBCDAD\nBCACCC\nCHROMO\nSOME\nCQFD" |sed -e "/\([A-Z]\).*\1/d";
      cela retourne :
      ABCD
      SOME
      CQFD

      En espérant aider quelqu'un.
      (par ailleurs, c'est une page très intéressante pour les rappels, merci)
      Stéphane

      Supprimer
  11. Bonjour,
    Pour chaque ligne d'un fichierX, je voudrais remplacer toutes les balises qui commencent par par la balise . La problématique est que la ligne peut comporter plusieurs caractères < et >
    Pour exemmple, remplacer :



    Par :




    Merci d'avance pour votre aide

    RépondreSupprimer
  12. Bonjour,
    Pour chaque ligne d'un fichierX, je voudrais remplacer toutes les balises qui commencent par "" par ". La problématique est que la ligne peut comporter plusieurs caractères < et >

    Merci

    RépondreSupprimer
  13. Bonjour,
    Pour chaque ligne d'un fichierX, je voudrais remplacer toutes les balises qui commencent par "GETAUX.." par "GETAUX". La problématique est que la ligne peut comporter plusieurs caractères " et "

    En clair, susbstituer toutes les lignes qui commenecent par "GETAUX jusqu'au 1er " rencontré par "GETAUX"

    Merci

    Merci

    RépondreSupprimer
  14. Salut ! Tout le monde, j'ai trouvé intéressante le tutoriel et les commentaires.

    J'aimerai pouvoir remplacer dans un fichier entre deux balises une valeur indiquée.

    RépondreSupprimer
    Réponses
    1. Bonjour,
      Remplacement d'une valeur entre 2 balises (exemple sous linux)

      echo "debut3.14fin" |sed -e 's:\(\).*\(<\/TAG>\):\1PI\2:';
      donne:
      debutPIfin

      En espérant aider quelqu'un.
      Stéphane

      Supprimer
    2. Correction:
      echo 'debut BALISE 3.14 /BALISE fin' |sed -e 's:\(BALISE\).*\(\/BALISE\):\1 pi \2:';
      debut BALISE pi /BALISE fin

      Remplacer BALISE par ce qui vous intéresse.
      (petit problème d'affichage de la réponse
      avec (caractère INF)BALISE(caractère SUP)
      Désolé
      Stéphane

      Supprimer
  15. Bonjour,
    Réponse pour "GETAUX... en début de ligne

    echo -e "\"GETAUX1 un peu\" tagada \"suite\" \"GETAUX 2\" \"UN\"\n\"GETAUX 3 beaucoup \" tsoin-tsoin \"DEUX\"\nTROIS\"GETAUX4 pas du tout\" fin"
    donne:
    "GETAUX1 un peu" tagada "suite" "GETAUX 2" "UN"
    "GETAUX 3 beaucoup " tsoin-tsoin "DEUX"
    TROIS"GETAUX4 pas du tout" fin

    mais avec |sed -e 's:^"GETAUX\([^"]*\)":"GETAUX":g'
    on a:
    "GETAUX" tagada "suite" "GETAUX 2" "UN"
    "GETAUX" tsoin-tsoin "DEUX"
    TROIS"GETAUX4 pas du tout" fin

    Est-ce que cela répond bien à la question ?

    RépondreSupprimer