<chapter id="chap_05">
<title>L'éditeur de flot GNU sed</title>
<abstract>
<para>À la fin de ce chapitre vous aurez connaissance des sujets 
suivants&nbsp;:</para>
<para><itemizedlist>
<listitem><para>Qu'est-ce que <command>sed</command>&nbsp;?</para></listitem>
<listitem><para>L'usage en mode immédiat de <command>sed</command></para></listitem>
<listitem><para>Les expressions régulières et l'édition de flot</para></listitem>
<listitem><para>Utiliser des commandes <command>sed</command> dans un script</para></listitem>
</itemizedlist></para>
<para>
<note><title>Ceci est une introduction</title>
<para>Ces explications sont loin d'être complètes et certainement pas faites pour être considérées comme le manuel utilisateur de <command>sed</command>.  Ce chapitre est seulement inclus afin de montrer quelques aspects intéressants dans les chapitres suivants, et parce que tout utilisateur avancé devrait avoir une connaissance de base de cet éditeur.</para>
<para>Pour plus d'informations, se référer aux pages man et info de <command>sed</command>.</para>
</note>
</para>
</abstract>

<sect1 id="sect_05_01"><title>Introduction</title>
<sect2 id="sect_05_01_01"><title>Qu'est-ce que sed&nbsp;?</title>
<para>Un <application>éditeur de flot (Stream EDitor)</application> est utilisé pour effectuer des transformations simples sur du texte lu depuis un fichier ou un tube (NdT&nbsp;: pipe).  Le résultat est envoyé sur la sortie standard.  La syntaxe de la commande <command>sed</command> ne spécifie pas de fichier de sortie, mais les résultats peuvent être mémorisés dans un fichier par le biais de redirection.  L'éditeur ne modifie pas le flot d'entrée.</para>
<para>Ce qui distingue <command>sed</command> d'autres éditeurs tel <command>vi</command> et <command>ed</command>, c'est sa faculté de filtrer le texte qu'il obtient par un tube.  Vous n'avez pas à interagir avec l'éditeur pendant qu'il travaille&nbsp;; c'est pourquoi  <command>sed</command> est parfois appelé un <emphasis>éditeur par lot</emphasis>.  Cette caractéristique vous permet d'utiliser des commandes d'édition dans un script, ce qui facilite grandement les tâches d'édition répétitives.  Quand vous devez effectuer un remplacement de texte dans un grand nombre de fichiers, <command>sed</command> est d'une grande aide.</para>
</sect2>
<sect2 id="sect_05_01_02"><title>commandes sed</title>
<para>Le programme <command>sed</command> peut effectuer substitutions et suppressions avec des expressions régulières, comme celles utilisées avec la commande <command>grep</command>&nbsp;; voir <xref linkend="sect_04_02" />.</para>
<para>Les commandes d'édition sont similaires à celles utilisées dans l'éditeur <command>vi</command>&nbsp;:</para>


<table id="tab_05_01" frame="all"><title>Commandes d'édition Sed</title>
<tgroup cols="2" align="left" colsep="1" rowsep="1">
<thead>
<row><entry>Commande</entry><entry>Effet</entry></row>
</thead>
<tbody>
<row><entry>a\</entry><entry>Ajoute le texte sous la ligne courante.</entry></row>
<row><entry>c\</entry><entry>Remplace le texte de la ligne courante par le nouveau texte.</entry></row>
<row><entry>d</entry><entry>Supprime le texte.</entry></row>
<row><entry>i\</entry><entry>Insère le texte au dessus de la ligne courante.</entry></row>
<row><entry>p</entry><entry>Imprime le texte.</entry></row>
<row><entry>r</entry><entry>Lit un fichier.</entry></row>
<row><entry>s</entry><entry>Cherche et remplace du texte.</entry></row>
<row><entry>w</entry><entry>Ecrit dans un fichier.</entry></row>
</tbody>
</tgroup>
</table>

<para>A part les commandes d'édition, vous pouvez donner des options à <command>sed</command>.  Un aperçu se trouve dans le tableau ci-dessous&nbsp;:</para>

<table id="tab_05_02" frame="all"><title>Options Sed</title>
<tgroup cols="2" align="left" colsep="1" rowsep="1">
<thead>
<row><entry>Option</entry><entry>Effet</entry></row>
</thead>
<tbody>
<row><entry><option>-e SCRIPT</option></entry><entry>Ajoute les commandes de SCRIPT au jeu de commandes à exécuter sur le flot en entrée.</entry></row>
<row><entry><option>-f</option></entry><entry>Ajoute les commandes contenues dans le fichier SCRIPT-FILE au jeu de commandes à exécuter sur le flot d'entrée.</entry></row>
<row><entry><option>-n</option></entry><entry>Mode Silencieux.</entry></row>
<row><entry><option>-V</option></entry><entry>Affiche les informations de version et s'arrête.</entry></row>
</tbody>
</tgroup>
</table>
<para>Les pages info de <command>sed</command> contiennent plus d'informations&nbsp;; nous ne listons ici que les commandes et les options le plus fréquemment utilisé.</para>
</sect2>


</sect1>
<sect1 id="sect_05_02"><title>Opérations d'édition de modification</title>
<sect2 id="sect_05_02_01"><title>Afficher les lignes contenant un patron</title>
<para>Vous pouvez le faire avec <command>grep</command>, bien sûr, mais vous ne pouvez faire un <quote>chercher-remplacer</quote> avec cette commande.  Ceci est juste un début.</para>
<para>Voici notre fichier texte d'exemple&nbsp;:</para>
<screen>
<prompt>sandy ~&gt;</prompt> <command>cat <option>-n</option> <filename>exemple</filename></command>
     1  This is the first line of an example text.
     2  It is a text with erors.
     3  Lots of erors.
     4  So much erors, all these erors are making me sick.
     5  This is a line not containing any errors.
     6  This is the last line.

<prompt>sandy ~&gt;</prompt>
</screen>
<para>Nous voulons que <command>sed</command> trouve toutes les lignes contenant le patron ciblé, dans ce cas <quote>erors</quote>.  Nous employons le <command>p</command> pour obtenir le resultat&nbsp;:</para>
<screen>
<prompt>sandy ~&gt;</prompt> <command>sed  <parameter>'/erors/p'</parameter> <filename>exemple</filename></command>
This is the first line of an example text.
It is a text with erors.
It is a text with erors.
Lots of erors.
Lots of erors.
So much erors, all these erors are making me sick.
So much erors, all these erors are making me sick.
This is a line not containing any errors.
This is the last line.

<prompt>sandy ~&gt;</prompt>
</screen>
<para>Comme vous l'avez remarqué, <command>sed</command> affiche le fichier entier, mais les lignes contenant la cible sont affichées 2 fois.  Ce n'est pas ce qu'on veut.  De sorte à n'afficher que les lignes contenant la cible, employez l'option <option>-n</option>&nbsp;:</para>
<screen>
<prompt>sandy ~&gt;</prompt> <command>sed <option>-n</option> <parameter>'/erors/p'</parameter> <filename>exemple</filename></command>
It is a text with erors.
Lots of erors.
So much erors, all these erors are making me sick.

<prompt>sandy ~&gt;</prompt>
</screen>
</sect2>
<sect2 id="sect_05_02_02"><title>Exclure les lignes contenant le patron</title>
<para>Nous utilisons le même exemple de fichier texte.  Maintenant nous voulons seulement voir les lignes qui ne contiennent <emphasis>pas</emphasis>  la chaîne cible&nbsp;:</para>
<screen>
<prompt>sandy ~&gt;</prompt> <command>sed <parameter>'/erors/d'</parameter> <filename>exemple</filename></command>
This is the first line of an example text.
This is a line not containing any errors.
This is the last line.

<prompt>sandy ~&gt;</prompt>
</screen>
<para>La commande <command>d</command> a pour effet d'exclure des lignes de l'affichage.</para>
<para>Les lignes dont le début correspond à un patron donné et la fin à un autre sont affichées comme ça&nbsp;:</para>
<screen>
<prompt>sandy ~&gt;</prompt> <command>sed <option>-n</option> <parameter>'/^This.*errors.$/p'</parameter> <filename>exemple</filename></command>
This is a line not containing any errors.

<prompt>sandy ~&gt;</prompt>
</screen>

</sect2>
<sect2 id="sect_05_02_03"><title>Intervalle de lignes</title>
<para>Cette fois nous voulons supprimer les lignes contenant les erreurs.  Dans l'exemple ce sont les lignes 2 à 4.  Spécifier cet intervalle avec la commande <command>d</command>&nbsp;:</para>
<screen>
<prompt>sandy ~&gt;</prompt> <command>sed <parameter>'2,4d'</parameter> <filename>exemple</filename></command>
This is the first line of an example text.
This is a line not containing any errors.
This is the last line.

<prompt>sandy ~&gt;</prompt>
</screen>
<para>Pour afficher le fichier à partir d'une certaine ligne jusqu'à la fin, employez une commande de la sorte&nbsp;:</para>
<screen>
<prompt>sandy ~&gt;</prompt> <command>sed <parameter>'3,$d'</parameter> <filename>exemple</filename></command>
This is the first line of an example text.
It is a text with erors.

<prompt>sandy ~&gt;</prompt>
</screen>
<para>Ceci affiche seulement les 2 premières lignes du fichier exemple.</para>
<para>Les commandes suivantes affichent la première ligne contenant le patron <quote>a text</quote>, jusqu'à et inclus la prochaine ligne contenant <quote>a line</quote>&nbsp;:</para>
<screen>
<prompt>sandy ~&gt;</prompt> <command>sed <option>-n</option> <parameter>'/a text/,/This/p'</parameter> <filename>exemple</filename></command>
It is a text with erors.
Lots of erors.
So much erors, all these erors are making me sick.
This is a line not containing any errors.

<prompt>sandy ~&gt;</prompt>
</screen>
</sect2>
<sect2 id="sect_05_02_04"><title>Trouver et remplacer avec sed</title>
<para>Dans cet exemple de fichier, nous allons maintenant chercher et remplacer les erreurs au lieu de seulement sélectionner les lignes contenant la cible.</para>
<screen>
<prompt>sandy ~&gt;</prompt> <command>sed <parameter>'s/erors/errors/'</parameter> <filename>exemple</filename></command>
This is the first line of an example text.
It is a text with errors.
Lots of errors.
So much errors, all these erors are making me sick.
This is a line not containing any errors.
This is the last line.

<prompt>sandy ~&gt;</prompt>
</screen>
<para>Comme vous le constatez, ce n'est pas exactement l'effet désiré&nbsp;: en ligne 4, seulement la première occurrence de la chaîne a été remplacée, et il reste encore un 'eror'.  Employer la commande <command>g</command> pour indiquer à <command>sed</command> qu'il doit traiter la ligne entière plutôt que de stopper à la première occurrence trouvée&nbsp;:</para>
<screen>
<prompt>sandy ~&gt;</prompt> <command>sed <parameter>'s/erors/errors/g'</parameter> <filename>exemple</filename></command>
This is the first line of an example text.
It is a text with errors.
Lots of errors.
So much errors, all these errors are making me sick.
This is a line not containing any errors.
This is the last line.

<prompt>sandy ~&gt;</prompt>
</screen>
<para>Pour insérer une chaîne au début de chaque ligne du fichier, par exemple pour citer&nbsp;:</para>
<screen>
<prompt>sandy ~&gt;</prompt> <command>sed <parameter>'s/^/&gt; /'</parameter> <filename>exemple</filename></command>
&gt; This is the first line of an example text.
&gt; It is a text with erors.
&gt; Lots of erors.
&gt; So much erors, all these erors are making me sick.
&gt; This is a line not containing any errors.
&gt; This is the last line.

<prompt>sandy ~&gt;</prompt>
</screen>
<para>Insérer une chaîne à la fin de chaque ligne&nbsp;:</para>
<screen>
<prompt>sandy ~&gt;</prompt> <command>sed <parameter>'s/$/EOL/'</parameter> <filename>exemple</filename></command>
This is the first line of an example text.EOL
It is a text with erors.EOL
Lots of erors.EOL
So much erors, all these erors are making me sick.EOL
This is a line not containing any errors.EOL
This is the last line.EOL

<prompt>sandy ~&gt;</prompt>
</screen>
<para>Commandes de recherche et remplacement multiples sont séparées avec l'option  <option>-e</option>&nbsp;:</para>
<screen>
<prompt>sandy ~&gt;</prompt> <command>sed <option>-e</option> <parameter>'s/erors/errors/g'</parameter> <option>-e</option> <parameter>'s/last/final/g'</parameter> <filename>exemple</filename></command>
This is the first line of an example text.
It is a text with errors.
Lots of errors.
So much errors, all these errors are making me sick.
This is a line not containing any errors.
This is the final line.

<prompt>sandy ~&gt;</prompt>
</screen>
<para>Garder à l'esprit que <command>sed</command> par défaut affiche les résultats sur la sortie standard, le plus souvent sur la fenêtre de votre terminal.  Si vous voulez sauvegarder le résultat dans un fichier, le rediriger&nbsp;:</para>
<cmdsynopsis><command>sed <option>option</option> <function>'some/expression'</function> <filename>file_to_process</filename> &gt; <filename>sed_output_in_a_file</filename></command></cmdsynopsis>
<tip><title>Plus d'exemples</title>
<para>Plein d'exemples <command>sed</command> se trouvent dans les scripts de démarrage de votre machine, lesquels sont d'ordinaire dans <filename>/etc/init.d</filename> ou <filename>/etc/rc.d/init.d</filename>.  Placez-vous dans le répertoire contenant les scripts d'initialisation de votre système et lancer la commande suivante&nbsp;:</para>
<cmdsynopsis><command>grep <parameter>sed</parameter> <filename>*</filename></command></cmdsynopsis>
</tip>
</sect2>

</sect1>
<sect1 id="sect_05_03"><title>L'usage en mode différé de sed</title>
<sect2 id="sect_05_03_01"><title>Lire des commandes sed depuis un fichier</title>
<para>De multiples commandes <command>sed</command> peuvent être mémorisées dans un fichier et exécutées avec l'option <option>-f</option>.  Quand un tel fichier est créé, assurez-vous que&nbsp;:</para>
<itemizedlist>
<listitem><para>Aucun espace n'est présent à la fin des lignes.</para></listitem>
<listitem><para>Aucune apostrophe n'est employée.</para></listitem>
<listitem><para>Quand vous entrez du texte à ajouter ou remplacer, toutes sauf la dernière ligne finit par un slash inversé.</para></listitem>
</itemizedlist>
</sect2>
<sect2 id="sect_05_03_02"><title>Ecrire des fichiers de résultat</title>
<para>Produire ce fichier se fait avec l'opérateur de redirection de sortie <command>&gt;</command>.  Ceci est un script d'exemple utile à la création de fichier HTML très simple à partir de fichiers texte simples.</para> 
<screen>
<prompt>sandy ~&gt;</prompt> <command>cat <filename>script.sed</filename></command>
1i\
&lt;html&gt;\
&lt;head&gt;&lt;title&gt;sed generated html&lt;/title&gt;&lt;/head&gt;\
&lt;body bgcolor="#ffffff"&gt;\
&lt;pre&gt;
$a\
&lt;/pre&gt;\
&lt;/body&gt;\
&lt;/html&gt;

<prompt>sandy ~&gt;</prompt> <command>cat <filename>txt2html.sh</filename></command>
#!/bin/bash

# Ceci est un script simple pour convertir du texte en HTML.
# D'abord nous éliminons tous les caractères de saut de ligne, de sorte que l'ajout
# ne se produise qu'une fois, puis nous remplaçons les sauts de ligne.

echo "converting $1..."

SCRIPT="/home/sandy/scripts/script.sed"
NAME="$1"
TEMPFILE="/var/tmp/sed.$PID.tmp"
sed "s/\n/^M/" $1 | sed -f $SCRIPT | sed "s/^M/\n/" &gt; $TEMPFILE
mv $TEMPFILE $NAME

echo "done."

<prompt>sandy ~&gt;</prompt>
</screen>
<para><varname>$1</varname> stocke le premier paramètre d'une commande donnée, dans ce cas le nom du fichier à convertir&nbsp;:</para>
<screen>
<prompt>sandy ~&gt;</prompt> <command>cat <filename>test</filename></command>
line1
line2
line3
</screen>
<para>Plus sur les paramètres positionnels au <xref linkend="chap_07" />.</para>
<screen>
<prompt>sandy ~&gt;</prompt> <command>txt2html.sh <filename>test</filename></command>
converting test...
done.

<prompt>sandy ~&gt;</prompt> <command>cat <filename>test</filename></command>
&lt;html&gt;
&lt;head&gt;&lt;title&gt;sed generated html&lt;/title&gt;&lt;/head&gt;
&lt;body bgcolor="#ffffff"&gt;
&lt;pre&gt;
line1
line2
line3
&lt;/pre&gt;
&lt;/body&gt;
&lt;/html&gt;

<prompt>sandy ~&gt;</prompt>
</screen>
<para>Ce n'est pas vraiment la bonne méthode&nbsp;; c'est juste un exemple pour démontrer le potentiel de  <command>sed</command>.  Voir la <xref linkend="sect_06_03" /> pour une solution plus décente à ce problème, avec les constructions <command>awk</command> <emphasis>BEGIN</emphasis> et <emphasis>END</emphasis>.</para>
<note><title>sed facile</title>
<para>Les éditeurs sophistiqués, permettant la mise en relief de la syntaxe, reconnaissent la syntaxe <command>sed</command>.  Cela peut être d'une grande aide si vous avez tendance à oublier des slashs inversés.</para></note>  
</sect2>

</sect1>
<sect1 id="sect_05_04"><title>Résumé</title>
<para>L'éditeur par lot <command>sed</command> est un outil puissant de travail sur une ligne, lequel peut traiter des flots de données&nbsp;: il peut prendre en entrée les lignes depuis un tube.  Ce qui le rend pratique pour un usage différé.  L'<command>éditeur sed</command> utilise des commandes de type <command>vi</command>  et accepte les expressions régulières.</para>
<para>L'outil <command>sed</command> peut lire des commandes depuis la ligne de commande ou depuis un script.  Il est souvent employé pour effectuer des chercher-remplacer sur des lignes contenant un patron.</para>

</sect1>
<sect1 id="sect_05_05"><title>Exercices</title>
<para>Ces exercices sont faits pour montrer plus avant ce que <command>sed</command> peut faire.</para>

<orderedlist>
<listitem><para>Afficher une liste des fichiers de votre répertoire de <filename>scripts</filename> qui se finissent par <quote>.sh</quote>.  Pensez que vous devrez peut-être supprimer l'alias <command>ls</command>.  Mettre le résultat dans un fichier temporaire.</para></listitem>
<listitem><para>Faire une liste des fichiers de <filename>/usr/bin</filename> qui ont la lettre <quote>a</quote> en second caractère.  Mettre le résultat dans un fichier temporaire.</para></listitem>
<listitem><para>Supprimer les 3 premières lignes de chaque fichier temporaire.</para></listitem>
<listitem><para>Afficher sur la sortie standard seulement les lignes contenant le patron  <quote>an</quote>.</para></listitem>
<listitem><para>Créer un fichier contenant les commandes <command>sed</command> pour effectuer les 2 tâches précédentes.  Ajouter une commande supplémentaire à ce fichier qui ajoute une chaîne comme <quote>*** Ceci pourrait avoir quelque chose à voir avec man et les pages man ***</quote> dans la ligne précédant chaque occurrence de la chaîne <quote>man</quote>.  Vérifier les résultats.</para></listitem>
<listitem><para>Une liste étendue du répertoire racine, <filename>/</filename>, est utilisée en entrée.  Créer un fichier stockant les commandes <command>sed</command> qui cherchent les liens symboliques et les fichiers simples.  Si un fichier est un lien symbolique, faire précéder la ligne de <quote>--Ceci est un  symlink--</quote>.  Si le fichier est un fichier simple, mettre un message sur la ligne, en ajoutant un commentaire du genre <quote>&lt;--- Ceci est un fichier simple</quote>.</para></listitem>
<listitem><para>Créer un script qui affiche les lignes, prises dans un fichier, contenant des espaces à la fin.  Ce script devrait faire appel à un script <command>sed</command> et afficher des informations utiles à l'utilisateur.</para>
</listitem>
</orderedlist>

</sect1>
</chapter>