<chapter id="chap_06">
<title>Le langage de programmation GNU awk</title>
<abstract>

<para>Dans ce chapitre nous aborderons&nbsp;:</para>
<para><itemizedlist>
<listitem><para>Qu'est-ce que <application>gawk</application>&nbsp;?</para></listitem>
<listitem><para>L'emploi de commandes <application>gawk</application> sur la ligne de commande</para></listitem>
<listitem><para>Comment formater du texte avec <application>gawk</application></para></listitem>
<listitem><para>Comment <application>gawk</application> utilise les expressions régulières</para></listitem>
<listitem><para><application>Gawk</application> dans les scripts</para></listitem>
<listitem><para><application>Gawk</application> et les variables</para></listitem>
</itemizedlist></para>
<para><note><title>Pour s'amuser un peu</title>
<para>

Comme pour <command>sed</command>, de nombreux livres ont été écrits sur 
les nombreuses versions de <command>awk</command>. Cette introduction 
est loin d'être complète et vise seulement à faire comprendre les 
exemples des chapitres suivants.. Pour approfondir, le mieux est de 
débuter avec la documentation qui accompagne <application>GNU 
awk</application>&nbsp;: <quote>GAWK: Effective AWK 
Programming: A User's Guide for GNU 
Awk</quote>.</para></note>

</para></abstract>

<sect1 id="sect_06_01"><title>Commencer avec gawk</title>
<sect2 id="sect_06_01_01"><title>Qu'est-ce que gawk&nbsp;?</title>
        <para><application>Gawk<indexterm><primary>gawk</primary><secondary>awk</secondary></indexterm></application> est la version GNU du programme couramment disponible sous UNIX <command>awk</command> <indexterm><primary>awk</primary><secondary>definition</secondary></indexterm>, un autre éditeur par lot populaire.  Du fait que le programme <command>awk</command> n'est souvent qu'un lien vers  <command>gawk</command>, nous nous y référerons en tant que <command>awk</command>.</para>
<para>La fonction de base de <command>awk</command> est de chercher dans des fichiers des lignes ou portion de texte contenant un ou des patrons.  Quand on trouve dans la ligne un des patrons, des actions sont effectuées sur cette ligne.</para>
<para>Un programme en <command>awk</command> est différent de la plupart des programmes en d'autres langages parce que un programme <command>awk</command> est <quote>construit sur les données</quote>&nbsp;: vous décrivez les données que vous voulez traiter puis le traitement à effectuer si elles sont trouvées.  La plupart des langages sont <quote>procéduraux.</quote> Vous devez décrire en détail chacune des étapes du processus.  En travaillant avec des langages procéduraux, il est généralement plus difficile de clairement décrire les données que le programme traitera.  Pour cette raison, un programme <command>awk</command> est souvent agréablement facile à lire et à écrire.</para>
<note><title>Qu'est-ce que cela veut dire&nbsp;?</title>
<para>dans les années 1970, 3 programmeurs se sont joints pour créer le langage.  Leurs noms étaient Aho, Kernighan et Weinberger.  Ils prirent la première lettre de chacun de leur nom pour nommer ce langage.  Donc le nom du langage aurait aussi bien pu être <quote>wak</quote>.</para>
</note>
</sect2>
<sect2 id="sect_06_01_02"><title>Commandes Gawk</title>
<para>Quand vous lancez <command>awk</command>, vous spécifiez un <emphasis>programme</emphasis>  <command>awk</command> qui indique à <command>awk</command> quoi faire.  Le programme consiste en une série de <emphasis>règles</emphasis>.  (Il peut aussi contenir des définitions de fonctions, de boucles, des conditions et autres possibilités que nous ignorerons pour l'instant.) Chaque règle spécifie un patron à cibler et une action à effectuer sur les cibles trouvées.</para>
<para>Il y a plusieurs façons de lancer <command>awk</command>.  Si le programme est court, il est plus facile de le lancer depuis la ligne de commande<indexterm><primary>awk</primary><secondary>program on the command line</secondary></indexterm>&nbsp;:</para>
<cmdsynopsis><command>awk PROGRAM <filename>inputfile(s)</filename></command></cmdsynopsis>
<para>Si de multiples changements doivent être fait, peut-être régulièrement sur de multiples fichiers, il est plus facile de mémoriser les commandes <command>awk</command><indexterm><primary>awk</primary><secondary>program script</secondary></indexterm> dans un script.   Ce qui se lit comme ceci&nbsp;:</para>
<cmdsynopsis><command>awk <option>-f</option> <filename>PROGRAM-FILE</filename> <filename>inputfile(s)</filename></command></cmdsynopsis>
</sect2>

</sect1>

<sect1 id="sect_06_02"><title>Le programme d'affichage</title>
<sect2 id="sect_06_02_01"><title>Afficher les champs sélectionnés</title>
<para>La commande <command>print</command> de <command>awk</command> affiche les données sélectionnées<indexterm><primary>awk</primary><secondary>print program</secondary></indexterm> depuis le fichier d'entrée.</para>
<para>Quand <command>awk</command> lit une ligne d'un fichier, il divise la ligne en champs basé sur le <emphasis>séparateur de champs en entrée</emphasis>, <varname>FS</varname>, qui est une variable  <command>awk</command> (voir <xref linkend="sect_06_03_02" />).  Cette variable est prédéfinie avec un ou plusieurs espaces et tabulations.</para>
<para>Les variables <varname>$1</varname>, <varname>$2</varname>, <varname>$3</varname>, ..., <varname>$N</varname> stockent les valeurs du premier, second, troisième jusqu'au dernier champ de la ligne traitée<indexterm><primary>awk</primary><secondary>input interpretation</secondary></indexterm>.  La variable <varname>$0</varname> (zéro) stocke la valeur de la ligne entière.  Ceci est illustré dans l'image ci-dessous, où nous voyons 6 colonnes dans l'affichage de la commande <command>df</command> &nbsp;:</para>
<figure><title>Les champs dans awk</title>
<mediaobject>
<imageobject>
<imagedata fileref="&images;awk.eps" format="EPS"></imagedata>
</imageobject>
<imageobject>
<imagedata fileref="&images;awk.png" format="PNG"></imagedata>
</imageobject>
<textobject>
<phrase>Les champs sont interprétés par awk&nbsp;: la première colonne est $1, la seconde est $2 etc.</phrase>
</textobject>
</mediaobject>
</figure>
<para>Dans le résultat de <command>ls <option>-l</option></command>, il y a 9 colonnes.  L'instruction <command>print</command> utilise ces  champs<indexterm><primary>awk</primary><secondary>example fields</secondary></indexterm> comme ceci&nbsp;:</para>
<screen>
<prompt>kelly@octarine ~/test&gt;</prompt> <command>ls <option>-l</option> | awk <parameter>'{ print $5 $9 }'</parameter></command>
160orig
121script.sed
120temp_file
126test
120twolines
441txt2html.sh

<prompt>kelly@octarine ~/test&gt;</prompt>
</screen>
<para>Cette commande a affiché la 5ème colonne d'une longue liste de fichiers, contenant la taille du fichier, et la dernière colonne, contenant le nom du fichier.  Ce résultat est peu lisible à moins d'utiliser le moyen ad hoc qui est de séparer les colonnes que vous voulez voir afficher par une virgule.  Dans ce cas, le caractère séparateur d'affichage par défaut, souvent un espace, sera inséré entre chaque champs de résultat.</para>

</sect2>

<sect2 id="sect_06_02_02"><title>Formater les champs</title>
<para>Sans formater, avec seulement le séparateur de résultat, l'affichage est peu lisible.  En insérant quelques tabulations<indexterm><primary>awk</primary><secondary>field formatting</secondary></indexterm> et une chaîne pour indiquer la nature du champs ce sera bien mieux&nbsp;:</para>
<screen>
<prompt>kelly@octarine ~/test&gt;</prompt> <command>ls <option>-ldh</option> <filename>*</filename> | grep <option>-v</option> <parameter>total</parameter> | \ 
awk <parameter>'{ print "Size is " $5 " bytes for " $9 }'</parameter></command>
Size is 160 bytes for orig
Size is 121 bytes for script.sed
Size is 120 bytes for temp_file
Size is 126 bytes for test
Size is 120 bytes for twolines
Size is 441 bytes for txt2html.sh

<prompt>kelly@octarine ~/test&gt;</prompt>
</screen>
<para>Notez l'effet du slash inversé, qui permet de continuer une entrée trop longue sur la ligne suivante sans que le Shell interprète cela comme des commandes distinctes.  Alors qu'une ligne de commande peut être en théorie de taille illimitée, celle du moniteur ne l'est pas, et encore moins celle du papier.  L'usage du slash inversé permet aussi le copier/coller de la ligne dans une fenêtre de terminal.</para>
<para>L'option <option>-h</option> de <command>ls</command> permet d'obtenir un format lisible de la taille des gros fichiers.  L'affichage d'une longue liste avec la somme des blocs du répertoire indiquée est produite quand un répertoire est le paramètre.  Cette ligne est inutile pour nous, donc nous avons mis un astérisque.  Nous avons aussi ajouté l'option <option>-d</option> pour la même raison, dans le cas où l'expansion de l'astérisque donne un répertoire.</para>
<para>Le slash inversé dans cet exemple marque la continuation de la ligne. Voir <xref linkend="sect_03_03_02" />.</para>
<para>On peut prendre en compte autant de colonnes que l'on veut et même bouleverser l'ordre.  Dans l'exemple ci-dessous on en trouve la démonstration qui affiche les partitions les plus critiques<indexterm><primary>awk</primary><secondary>formatting example</secondary></indexterm>&nbsp;:</para>
<screen>
<prompt>kelly@octarine ~&gt;</prompt> <command>df <option>-h</option> | sort <option>-rnk</option> <parameter>5</parameter> | head <parameter>-3</parameter> | \ 
awk <parameter>'{ print "Partition " $6 "\t: " $5 " full!" }'</parameter></command>
Partition /var  : 86% full!
Partition /usr  : 85% full!
Partition /home : 70% full!

<prompt>kelly@octarine ~&gt;</prompt>
</screen>
<para>Le tableau ci-dessous donne un aperçu des caractères spéciaux de formatage<indexterm><primary>awk</primary><secondary>formatting characters</secondary></indexterm>&nbsp;:</para>

<table id="tab_06_01" frame="all"><title>Caractères de formatage pour gawk</title><tgroup cols="2" align="left" colsep="1" rowsep="1"><thead>
<row><entry>Séquence</entry><entry>sens</entry></row>
</thead>
<tbody>
<row><entry>\a</entry><entry>sonnerie</entry></row>
<row><entry>\n</entry><entry>Saut de ligne</entry></row>
<row><entry>\t</entry><entry>Tabulation</entry></row>
</tbody>
</tgroup>
</table>
<para>L'apostrophe, le signe Dollar et autres métacaractères devraient être protégés avec un slash inversé .</para>
</sect2>


<sect2 id="sect_06_02_03"><title>La commande print et les expressions régulières</title>
<para>Une expression régulière peut être utilisée comme patron en l'enfermant entre slashs.  L'expression régulière<indexterm><primary>awk</primary><secondary>regular expressions</secondary></indexterm> est alors comparée à chaque enregistrement de texte.  La syntaxe est celle-ci&nbsp;:</para>
<cmdsynopsis><command>awk 'EXPRESSION  { PROGRAM }' <filename>file(s)</filename></command></cmdsynopsis>
<para>L'exemple suivant affiche seulement les informations des disques locaux, les systèmes de fichiers réseaux n'y sont pas<indexterm><primary>awk</primary><secondary>regexp example</secondary></indexterm>&nbsp;:</para>
<screen>
<prompt>kelly is in ~&gt;</prompt> <command>df <option>-h</option> | awk <parameter>'/dev\/hd/ { print $6 "\t: " $5 }'</parameter></command>
/       : 46%
/boot   : 10%
/opt    : 84%
/usr    : 97%
/var    : 73%
/.vol1  : 8%

<prompt>kelly is in ~&gt;</prompt>
</screen>
<para>Le Slash doit être protégé, parce qu'il a un sens spécial pour le programme  <command>awk</command>.</para>

<para>Ci-dessous un autre exemple où nous cherchons dans le répertoire  <filename>/etc</filename> les fichiers qui se terminent par <quote>.conf</quote> et qui commencent par  <quote>a</quote> <emphasis>ou</emphasis> <quote>x</quote>, en employant des expressions régulières étendues&nbsp;:</para>
<screen>
<prompt>kelly is in /etc&gt;</prompt> <command>ls <option>-l</option> | awk <parameter>'/\&lt;(a|x).*\.conf$/ { print $9 }'</parameter></command>
amd.conf
antivir.conf
xcdroast.conf
xinetd.conf

<prompt>kelly is in /etc&gt;</prompt>
</screen>
<para>Cet exemple illustre le sens spécial du point dans les expressions régulières&nbsp;: le premier indique que nous voulons cibler tout caractère après la première chaîne ciblée, le second est protégé parce que il fait partie d'une chaîne à cibler (la fin du nom de fichier).</para>
</sect2>
<sect2 id="sect_06_02_04"><title>Patrons particuliers</title>
<para>Afin de faire précéder le résultat par un commentaire<indexterm><primary>awk</primary><secondary>BEGIN</secondary></indexterm>, employer l'instruction   <command>BEGIN</command>&nbsp;:</para>
<screen>
<prompt>kelly is in /etc&gt;</prompt> <command>ls <option>-l</option> | \
awk <parameter>'BEGIN { print "Files found:\n" } /\&lt;[a|x].*\.conf$/ { print $9 }'</parameter></command>
Files found:
amd.conf
antivir.conf
xcdroast.conf
xinetd.conf

<prompt>kelly is in /etc&gt;</prompt>
</screen>

<para>L'instruction <command>END</command> peut être ajoutée pour insérer du texte après que le flot en entrée ait été entièrement traité&nbsp;:</para>
<screen>
<prompt>kelly is in /etc&gt;</prompt> <command>ls <option>-l</option> | \
awk <parameter>'/\&lt;[a|x].*\.conf$/ { print $9 } END { print \
"Can I do anything else for you, mistress?" }'</parameter></command>
amd.conf
antivir.conf
xcdroast.conf
xinetd.conf
Can I do anything else for you, mistress?

<prompt>kelly is in /etc&gt;</prompt>
</screen>


</sect2>
<sect2 id="sect_06_02_05"><title>Les scripts Gawk</title>
<para>Au fur et à mesure que les commandes deviennent complexes, vous voudrez les mémoriser dans un script<indexterm><primary>awk</primary><secondary>scripts</secondary></indexterm>,  pour être réemployées.  Un script <command>awk</command> contient des instructions <command>awk</command> définissant des patrons et des actions.</para>
<para>Pour illustrer nous allons produire un rapport qui affiche nos partitions les plus pleines<indexterm><primary>awk</primary><secondary>script example</secondary></indexterm>.  Voir <xref linkend="sect_06_02_02" />.</para>
<screen>
<prompt>kelly is in ~&gt;</prompt> <command>cat <filename>diskrep.awk</filename></command>
BEGIN { print "*** WARNING WARNING WARNING ***" }
/\&lt;[8|9][0-9]%/ { print "Partition " $6 "\t: " $5 " full!" }
END { print "*** Donnez de l'argent pour un nouveau disque VITE&nbsp;! ***" }

kelly is in ~&gt; df -h | awk -f diskrep.awk
*** WARNING WARNING WARNING ***
Partition /usr  : 97% full!
*** Donnez de l'argent pour un nouveau disque VITE&nbsp;! ***

<prompt>kelly is in ~&gt;</prompt>
</screen>
<para><command>awk</command> d'abord affiche le message de début, puis formate toutes les lignes qui contiennent un 8 ou un 9 au début de chaque mot, suivi par un autre chiffre et le signe de pourcentage.  Un message final est ajouté.</para>
<note><title>Mise en relief de la syntaxe</title>
<para>Awk est un langage de programmation .  Sa syntaxe est reconnue par la plupart des éditeurs qui font la mise en relief de la syntaxe comme pour d'autres langages tel que C, Bash, HTML, etc.</para></note>
</sect2>

</sect1>
<sect1 id="sect_06_03"><title>Les variables Gawk</title>
<para>Tandis que <command>awk</command> traite le fichier en entrée, il utilise plusieurs variables<indexterm><primary>awk</primary><secondary>variables</secondary></indexterm>.  Certaines sont modifiables, d'autres sont en lecture.</para>
<sect2 id="sect_06_03_01"><title>Le séparateur de champs en entrée</title>
<para>Le <emphasis>séparateur de champs<indexterm><primary>awk</primary><secondary>input field separator</secondary></indexterm></emphasis>, qui est soit un simple caractère, soit une expression régulière, contrôle la façon dont <command>awk</command> découpe l'enregistrement entré en champs.  L'enregistrement en entrée est examiné à la recherche de séquences de caractères qui correspondent au séparateur défini&nbsp;; les champs eux-mêmes sont les textes entre chaque séparateur.</para>
<para>Le séparateur de champs est défini par la variable intégrée <varname>FS</varname>.  Notez que cette variable et <varname>IFS</varname> utilisée par les Shell compatible  POSIX sont distinctes.</para>
<para> La valeur de la variable de séparateur de champs peut être changée dans le programme <command>awk</command> avec l'opérateur d'assignement <command>=</command>.  Souvent le bon moment pour faire ce changement c'est au début de l'exécution avant qu'aucune entrée n'ait été traitée, de sorte que le tout premier enregistrement est lu avec le séparateur idoine.  Pour ce faire employer le patron spécial <command>BEGIN</command>.</para>
<para>Dans l'exemple ci-dessous, nous écrivons une commande qui affiche tous les utilisateurs de votre système avec une description&nbsp;:</para>
<screen>
<prompt>kelly is in ~&gt;</prompt> <command>awk <parameter>'BEGIN { FS=":" } { print $1 "\t" $5 }'</parameter> <filename>/etc/passwd</filename></command>
--output omitted--
kelly   Kelly Smith
franky  Franky B.
eddy    Eddy White
willy   William Black
cathy   Catherine the Great
sandy   Sandy Li Wong

<prompt>kelly is in ~&gt;</prompt>
</screen>
<para>Dans un script <command>awk</command>, cela ressemblerait à ça&nbsp;:</para>
<screen>
<prompt>kelly is in ~&gt;</prompt> <command>cat <filename>printnames.awk</filename></command>
BEGIN { FS=":" }
{ print $1 "\t" $5 }

<prompt>kelly is in ~&gt;</prompt> <command>awk <option>-f</option> <filename>printnames.awk /etc/passwd</filename></command>
--output omitted--
</screen>
<para>Choisir un séparateur de champs d'entrée soigneusement pour éviter des soucis. Un exemple pour illustrer ceci&nbsp;: disons que vous obtenez l'entrée sous la forme de lignes qui ressemble à ça&nbsp;:</para>
<para><quote>Sandy L. Wong, 64 Zoo St., Antwerp, 2000X</quote></para>
<para>Vous écrivez une commande ou un script, qui affiche le nom de la personne dans cet enregistrement&nbsp;:</para>
<cmdsynopsis><command>awk 'BEGIN { FS="," } { print $1, $2, $3 }' <filename>inputfile</filename></command></cmdsynopsis>
<para>Mais une personne pourrait avoir un doctorat, et ça pourrait s'écrire comme ça&nbsp;:</para>
<para><quote>Sandy L. Wong, Doctorat, 64 Zoo St., Antwerp, 2000X</quote></para>
<para>Votre <command>awk</command> donnera un mauvais résultat sur cette ligne.  Au besoin faire un <command>awk</command> supplémentaire ou un <command>sed</command> pour uniformiser le format des données en entrée.</para>
<para>Le séparateur de champs en entrée est par défaut un ou des espaces ou des  tabulations.</para>
</sect2>
<sect2 id="sect_06_03_02"><title>Les séparateurs de résultat</title>
<sect3 id="sect_06_03_02_01"><title>Les séparateurs de champs de résultat</title>
<para>Les champs sont habituellement séparés par des espaces dans le résultat<indexterm><primary>awk</primary><secondary>output field separator</secondary></indexterm>.  Ceci est visible quand vous employez la syntaxe correcte pour la commande  <command>print</command> où les paramètres sont séparés par des virgules&nbsp;:</para>
<screen>
<prompt>kelly@octarine ~/test&gt;</prompt> <command>cat <filename>test</filename></command>
record1         data1
record2         data2

<prompt>kelly@octarine ~/test&gt;</prompt> <command>awk <parameter>'{ print $1 $2}'</parameter> <filename>test</filename></command>
record1data1
record2data2

<prompt>kelly@octarine ~/test&gt;</prompt> <command>awk <parameter>'{ print $1, $2}'</parameter> <filename>test</filename></command>
record1 data1
record2 data2

<prompt>kelly@octarine ~/test&gt;</prompt>
</screen>
<para>Si vous ne mettez pas de virgule, <command>print</command> considérera les éléments de résultat comme un seul argument, c'est à dire il omet l'emploi du <emphasis>séparateur de résultat</emphasis> par défaut, <varname>OFS</varname>.</para>
<para>N'importe quel caractère peut être employé comme séparateur de champs de résultat en définissant cette variable intégrée.</para>
</sect3>
<sect3 id="sect_06_03_02_02"><title>Le séparateur d'enregistrement de résultat</title>
<para>Le résultat d'une instruction <command>print</command> est appelée un <emphasis>enregistrement de résultat<indexterm><primary>awk</primary><secondary>output record separator</secondary></indexterm></emphasis>.  Chaque commande <command>print</command> produit un enregistrement de résultat, et ajoute une chaîne appelée le <emphasis>séparateur d'enregistrement de résultat</emphasis>, <varname>ORS</varname> (NdT&nbsp;: output record separator).  La valeur par défaut de cette variable est <quote>\n</quote>, le caractère saut de ligne.  Donc, chaque instruction <command>print</command> génère une ligne distincte.</para>
<para>Pour modifier la façon dont les champs et les enregistrements de résultat sont séparés, assignez une autre valeur à <varname>OFS</varname> et <varname>ORS</varname>&nbsp;:</para>
<screen>
<prompt>kelly@octarine ~/test&gt;</prompt> <command>awk <parameter>'BEGIN { OFS=";" ; ORS="\n--&gt;\n" } \
{ print $1,$2}'</parameter> <filename>test</filename></command>
record1;data1
--&gt;
record2;data2
--&gt;

<prompt>kelly@octarine ~/test&gt;</prompt>
</screen>
<para>Si la valeur de <varname>ORS</varname> ne contient pas de saut de ligne, le résultat global tiendra sur une seule ligne.</para>

</sect3>
</sect2>
<sect2 id="sect_06_03_03"><title>Le nombre d'enregistrements</title>
<para>L'intégré <varname>NR</varname> stocke le nombre d'enregistrements qui sont traités<indexterm><primary>awk</primary><secondary>number of records</secondary></indexterm>.  Il est incrémenté après la lecture d'une nouvelle ligne d'entrée.  Vous pouvez l'utiliser à la fin pour compter le nombre total d'enregistrements, ou à chaque enregistrement de résultat&nbsp;:</para>
<screen>
<prompt>kelly@octarine ~/test&gt;</prompt> <command>cat <filename>processed.awk</filename></command>
BEGIN { OFS="-" ; ORS="\n--&gt; done\n" }
{ print "Record number " NR ":\t" $1,$2 }
END { print "Number of records processed: " NR }

<prompt>kelly@octarine ~/test&gt;</prompt> <command>awk <option>-f</option> <filename>processed.awk test</filename></command>
Record number 1:        record1-data1
--&gt; done
Record number 2:        record2-data2
--&gt; done
Number of records processed: 2
--&gt; done

<prompt>kelly@octarine ~/test&gt;</prompt>
</screen>
</sect2>
<sect2 id="sect_06_03_04"><title>Les variables définies par l'utilisateur</title>
<para>En plus des variables intégrées, vous pouvez définir les vôtres.  Quand <command>awk</command> rencontre une référence à une variable<indexterm><primary>awk</primary><secondary>user defined variables</secondary></indexterm> qui n'existe pas (qui n'est pas prédéfinie), la variable est créée et initialisée à une chaîne nulle.  Pour toutes les références suivantes, la valeur de la variable est la dernière valeur affectée.  Une variable peut être une chaîne ou une valeur numérique.  Le contenu des champs en entrée peut aussi être affecté à une variable.</para>
<para>Une valeur peut être assignée directement par l'opérateur <command>=</command>, ou vous pouvez utiliser la valeur courante de la variable combinée avec d'autres opérateurs&nbsp;:</para>
<screen>
<prompt>kelly@octarine ~&gt;</prompt> <command>cat <filename>revenues</filename></command>
20021009        20021013        consultancy     BigComp         2500
20021015        20021020        training        EduComp         2000
20021112        20021123        appdev          SmartComp       10000
20021204        20021215        training        EduComp         5000

<prompt>kelly@octarine ~&gt;</prompt> <command>cat <filename>total.awk</filename></command>
{ total=total + $5 }
{ print "Send bill for " $5 " dollar to " $4 }
END { print "---------------------------------\nTotal revenue: " total }

<prompt>kelly@octarine ~&gt;</prompt> <command>awk <option>-f</option> <filename>total.awk test</filename></command>
Send bill for 2500 dollar to BigComp
Send bill for 2000 dollar to EduComp
Send bill for 10000 dollar to SmartComp
Send bill for 5000 dollar to EduComp
---------------------------------
Total revenue: 19500

<prompt>kelly@octarine ~&gt;</prompt>
</screen>

<para>Les raccourcis de type C comme <command><varname>VAR</varname>+= value</command> sont aussi acceptés.</para>
</sect2>

<sect2 id="sect_06_03_05"><title>Plus d'exemples</title>
<para>L'exemple de la <xref linkend="sect_05_03_02" /> devient bien plus facile quand on utilise un script <command>awk</command><indexterm><primary>awk</primary><secondary>example</secondary></indexterm>&nbsp;:</para>
<screen>
<prompt>kelly@octarine ~/html&gt;</prompt> <command>cat <filename>make-html-from-text.awk</filename></command>
BEGIN { print "&lt;html&gt;\n&lt;head&gt;&lt;title&gt;Awk-generated HTML&lt;/title&gt;&lt;/head&gt;\n&lt;body bgcolor=\"#ffffff\"&gt;\n&lt;pre&gt;" }
{ print $0 }
END { print "&lt;/pre&gt;\n&lt;/body&gt;\n&lt;/html&gt;" }
</screen>
<para>Et les commandes à exécuter sont aussi bien plus directe quand on utilise  <command>awk</command> plutôt que <command>sed</command>&nbsp;:</para>
<screen>
<prompt>kelly@octarine ~/html&gt;</prompt> <command>awk <option>-f</option> <filename>make-html-from-text.awk testfile</filename> &gt; <filename>file.html</filename></command>
</screen>
<tip><title>Exemples d'Awk sur votre système</title>
<para>Nous nous référons encore au répertoire qui contient les scripts d'initialisation de votre système. Entrez une commande similaire à la suivante pour voir d'autres exemples pratiques de l'usage très répandu de la commande <command>awk</command>&nbsp;:</para>
<cmdsynopsis><command>grep <parameter>awk</parameter> <filename>/etc/init.d/*</filename></command></cmdsynopsis>
</tip>
</sect2>
<sect2 id="sect_06_03_06"><title>Le programme printf</title>
<para>Pour un contrôle du format du résultat plus précis que celui fournit par <command>print</command>, employez <command>printf<indexterm><primary>awk</primary><secondary>printf program</secondary></indexterm></command>.  La commande <command>printf</command> peut spécifier une largeur de champs pour chaque élément, de même que divers choix de formatage des nombres (tel que la base de calcul à considérer, si il faut afficher un exposant, si le signe est à afficher, et combien de chiffres à afficher après la virgule).  Ceci est fait en ajoutant une chaîne appelée <emphasis>chaîne de formatage</emphasis>, qui contrôle comment et où afficher les autres arguments.</para>
<para>La syntaxe est la même que celle de l'instruction du langage C <command>printf</command>&nbsp;; voir votre guide d'instruction C.  Les pages info de <command>gawk</command> contiennent plein d'explications.</para>
</sect2>

</sect1>
<sect1 id="sect_06_04"><title>Résumé</title>
<para>L'utilitaire <command>gawk</command> interprète un langage de programmation à but spécial, prenant en charge les travaux de reformatage de données avec seulement quelques lignes de code.  C'est une version libre de la commande UNIX <command>awk</command>.</para>
<para>Cet outil lit les lignes de données entrées et peut aisément repérer le colonnage du résultat.  Le programme <command>print</command> est le plus courant pour filtrer et formater des champs définis.</para>
<para>La déclaration de variable au coup par coup est directe et permet des sommations simples, des statistiques et autres opérations sur le flot en entrée traité. Les variables et les commandes peuvent être insérées dans un script <command>awk</command> pour un traitement en tâche de fond.</para>
<para>Autres choses que vous devriez savoir à propos de <command>awk</command>&nbsp;:</para>
<itemizedlist>
<listitem><para>Le langage reste très répandu sur UNIX et ses clones, mais pour exécuter des tâches similaires <application>Perl</application> est maintenant plus souvent employé.  Cependant, <command>awk</command> a une courbe d'apprentissage plus rapide (c'est à dire que vous apprenez en peu de temps).  En d'autres mots, <application>Perl</application> est plus difficile à apprendre.</para></listitem>
<listitem><para>Les deux, <application>Perl</application> et <command>awk</command>, se partagent la réputation d'être incompréhensible, même pour les auteurs de programmes dans ces langages.  Donc annotez votre code&nbsp;!</para></listitem>
</itemizedlist>
</sect1>
<sect1 id="sect_06_05"><title>Exercices</title>

<para>Il y a quelques exemples concret où <command>awk</command> peut être pratique.</para>

<orderedlist>
<listitem><para>Pour le premier exercice, l'entrée sont les lignes de la forme suivante&nbsp;:</para>
<screen>Username:Firstname:Lastname:Telephone number</screen>
<para>Faire un script <command>awk</command> qui convertit une telle ligne en un enregistrement LDAP à ce format&nbsp;:</para>
<screen>
dn: uid=Username, dc=example, dc=com
cn: Firstname Lastname
sn: Lastname
telephoneNumber: Telephone number
</screen>
<para>Créer un fichier contenant quelques enregistrements de test et vérifiez..</para>
</listitem>
<listitem><para>Créer un script Bash utilisant <command>awk</command> et les commandes standard UNIX qui affiche les 3 utilisateurs les plus gros consommateurs d'espaces disques dans le répertoire <filename>/home</filename> (si il ne situe pas dans une partition distincte, faire le script pour la partition <filename>/</filename>&nbsp;; celle-ci existe sur tout système UNIX).  D'abord, exécutez les commandes depuis la ligne de commande.  Puis mettez-les dans un script.  Le script devrait produire un résultat compréhensible (lisible par le chef).  Si tout semble fonctionner, faire en sorte que le script vous envoie le résultat par mail (employez par exemple <command>mail <option>-s</option> <parameter>Disk space usage</parameter> <email>you@your_comp</email> &lt; <filename>result</filename></command>).</para>
<para>Si le démon des quotas tourne, utilisez ses informations&nbsp;; si non utilisez  <command>find</command>.</para>
</listitem>
<listitem>
<para>Créer un résultat de style XML à partir d'une liste séparée par des <keycap>tabulations</keycap> de la forme suivante&nbsp;:</para>
<screen>
Meaning very long line with a lot of description
 
meaning another long line
 
othermeaning    more longline
 
testmeaning     looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong line, but i mean really looooooooooooooooooooooooooooooooooooooooooooooooooong.
 
</screen>
<para>Le résultat devrait être&nbsp;:</para>
<screen>
&lt;row&gt;
&lt;entry&gt;Meaning&lt;/entry&gt;
&lt;entry&gt;
very long line
&lt;/entry&gt;
&lt;/row&gt;
&lt;row&gt;
&lt;entry&gt;meaning&lt;/entry&gt;
&lt;entry&gt;
long line
&lt;/entry&gt;
&lt;/row&gt;
&lt;row&gt;
&lt;entryothermeaning&lt;/entry&gt;
&lt;entry&gt;
more longline
&lt;/entry&gt;
&lt;/row&gt;
&lt;row&gt;
&lt;entrytestmeaning&lt;/entry&gt;
&lt;entry&gt;
looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong line, but i mean really looooooooooooooooooooooooooooooooooooooooooooooooooong.
&lt;/entry&gt;
&lt;/row&gt;
</screen>
<para>En plus, si vous connaissez quelque peu XML, écrivez un script BEGIN et END  pour compléter la table.  Ou faites le en HTML.</para>
</listitem>
</orderedlist>
</sect1>
</chapter>