<?xml version='1.0' encoding='iso-8859-1' standalone='no'?>
<!DOCTYPE article PUBLIC "-//OASIS//DTD DocBook XML V4.2//EN"  "/usr/local/share/xml/docbook/4.2/docbookx.dtd" [
<!ENTITY ie "<abbrev>i.e.</abbrev>">
<!ENTITY cf "<abbrev>c.f.</abbrev>">
<!ENTITY todo "<command>--- T O  D O :</command>">
<!ENTITY unix "<emphasis>Unix</emphasis>">
<!ENTITY bsd "<emphasis>BSD</emphasis>">
<!ENTITY xbsd "<emphasis>xBSD</emphasis>">
<!ENTITY fbsd "<emphasis >FreeBSD</emphasis>">
<!ENTITY sysV "<emphasis>System V</emphasis>">
<!ENTITY glinux "<emphasis >GNU/Linux</emphasis>">
<!ENTITY deb "<emphasis>Debian</emphasis>">
<!ENTITY inode "<foreignphrase>inode</foreignphrase>">
<!ENTITY inodes "<foreignphrase>inodes</foreignphrase>">
<!ENTITY filesystem "<foreignphrase>filesystem</foreignphrase>">
<!ENTITY awk "<command>awk</command>">
<!ENTITY sed "<command>sed</command>">
<!ENTITY verOBSD "3.4">
<!ENTITY _aut_Pre "<firstname>Pascal</firstname>">
<!ENTITY _aut_Nom "<surname>Picard</surname>">
<!ENTITY _aut_eMail "<email>pascal@seth.homeunix.net</email>">
<!ENTITY _aut_Init "<authorinitials>P.P.</authorinitials>">
<!ENTITY _affiliat "<affiliation><orgname>Corto E.T.F., K&amp;M</orgname><address>Sainte-Clotilde, Ile de la R&#233;union</address></affiliation>">
<!ENTITY _holder "<holder>Pascal PICARD, <emphasis>pascal@seth.homeunix.net</emphasis></holder>">
]>
<article class="techreport" lang="fr">
  <articleinfo>
    <author>
      <firstname>Pascal</firstname>

      <surname>Picard</surname>

      <affiliation>
        <orgname>Corto E.T.F., K&amp;M</orgname>

        <address>Sainte-Clotilde, Ile de la Réunion</address>
      </affiliation>
    </author>

    <author>
      <firstname>Ivan</firstname>

      <surname>Kurzweg</surname>

      <affiliation>
        <orgname>Fremens Institute.</orgname>

        <address>La Possession, Ile de la Réunion</address>
      </affiliation>
    </author>

    <title>Eléments de base</title>

    <copyright>
      <year>2003-2005, 2006</year>

      <holder>Pascal PICARD,<emphasis>pascal@seth.homeunix.net,
      2006</emphasis></holder>

      <holder>Ivan KURZWEG<emphasis> ik-r@wanadoo.fr, 2006</emphasis></holder>
    </copyright>

 

    <legalnotice>
      <para>Permission to use, copy, modify, and distribute this documentation
      for any purpose with or without fee is here by granted, provided that
      the above copyright notice and this permission notice appear in all
      copies.</para>

      <para>THE DOCUMENTATION IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL
      WARRANTIES WITH REGARD TO THIS DOCUMENTATION INCLUDING ALL IMPLIED
      WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR
      BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR
      ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS,
      WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION,
      ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS
      DOCUMENTATION.</para>
    </legalnotice>

    <keywordset>
      <keyword>pwd, cd, soft link, hard link, file, cat, mw, rm, who, id,
      hostname, cat, tac, more, less, sort, uniq, wc, tail, head, cut, nl, pr,
      expand, unexpand, tr, od, split, fmt, fold, paste, join, tee, awk,
      sed</keyword>
    </keywordset>
  </articleinfo>

  <abstract>
    <para>Nous aborderons dans une première partie, quelques commandes de
    bases de l'univers <emphasis>Unix</emphasis>. Puis nous mènerons dans la
    deuxième partie une étude, non exhaustive, des principaux utilitaires de
    gestion de texte.</para>

    <!-- VERSION ASR DEBUT -->

    <para>Nous proposons dans les deux parties suivantes quelques éléments
    d'initiation à  <command>awk</command> et <command>sed</command>.</para>

    <!-- VERSION ASR FIN -->

    <para>Enfin, pour nous joindre :
    <email>pascal@seth.homeunix.net</email><email>ik-r@wanadoo.fr</email></para>
  </abstract>

  <!-- ==================== 1e partie ==================== -->

  <sect1>
    <title>Commandes et notions de bases</title>

    <para>Cette partie présente de manière très générale quelques commandes
    des systèmes <emphasis>Unix</emphasis> sans rentrer dans le détail de
    toutes les options. La plupart seront revues de manière plus approfondies
    dans des chapitres ultérieurs et plus spécifiques. La consultation du
    <emphasis>man</emphasis> est impérative (rappel : <computeroutput>man
    &lt;commande&gt;</computeroutput>). <note>
        <para>Dans les extraits qui illustrent le comportement des commandes,
        j'utilise parfois le caractère #. Celui-ci est considéré comme un
        début de commentaire qui s'étend jusqu'à  la fin de la ligne, le
        système ignore tout ce qui fait suite à  ce caractère.</para>

        <para>Dans tous les exemples, le symbole $ désigne un utilisateur
        standard, sans privilège particulier.</para>

        <para>Enfin, dans les paragraphes qui suivent les termes référence et
        désignation sont des synonymes, ils sont donc interchangeables.</para>
      </note></para>

    <sect2>
      <title>chemins, chemins absolus et chemins relatifs</title>

      <para>Le système de fichiers dans l'environnement
      <emphasis>Unix</emphasis> est organisé sous forme arborescente<footnote>
          <para>Plus exactement, il s'agit d'un graphe acyclique, plusieurs
          désignations différentes pouvant aboutir à  la même ressource.
          L'acyclicité permettant de conserver des algorithmes
          <quote>simples</quote> pour la gestion de la structure de
          données.</para>
        </footnote>. Les noeuds internes de l'arbre sont généralement des
      répertoires (<abbrev>i.e.</abbrev> des fichiers au sens
      <emphasis>Unix</emphasis> contenant eux mêmes des fichiers simples ou
      des répertoires), tandis que les feuilles sont les fichiers. La
      désignation qui permet de nommer une ressource est un chemin.</para>

      <para>La racine de cette arborescence est dénotée par le symbole
      <emphasis role="bold">/</emphasis>, dit
      <foreignphrase>root</foreignphrase>. Tout chemin qui commence par ce
      symbole est dit absolu [<foreignphrase>absolute
      pathname</foreignphrase>] puisqu'il se réfère à  l'origine de la
      structure arborescente. Ainsi, les désignations suivantes sont des
      chemins absolus : <informalexample>
          <para><filename>/sbin</filename>,</para>
        </informalexample> <informalexample>
          <para><filename>/usr/local/bin</filename>,</para>
        </informalexample> <informalexample>
          <para><filename>/usr/X11R6/bin</filename>,</para>
        </informalexample></para>

      <para>Un chemin absolu n'est autre qu'un chemin relatif à  la racine (/)
      de l'arborescence. Si maintenant on veut désigner une ressource
      relativement à  l'endroit oà¹ l'on se trouve, on obtient un chemin
      relatif. Si, par exemple, je me trouve dans le répertoire
      <filename>/usr</filename>, alors les désignations suivantes sont des
      chemins relatifs [<foreignphrase>relatives pathnames</foreignphrase>] :
      <informalexample>
          <para><filename>local/bin</filename></para>
        </informalexample> <informalexample>
          <para><filename>X11R6/bin</filename></para>
        </informalexample></para>
    </sect2>

    <sect2>
      <title><command>pwd</command></title>

      <para>L'utilitaire <command>pwd (1)</command> [<foreignphrase>print
      working directory</foreignphrase>, situé dans <filename>/bin</filename>,
      section (1) du man], indique le répertoire courant dans lequel on se
      trouve. <programlisting width="80">
<emphasis>EXEMPLE :</emphasis>

$ pwd                                                                           
/home/pascal/lecture

</programlisting></para>
    </sect2>

    <sect2>
      <title><command>cd</command></title>

      <para>La commande interne <command>cd</command> [<foreignphrase>change
      directory</foreignphrase>], permet de naviguer dans l'arborescence. Son
      argument optionnel qui est un chemin relatif ou absolu permet de changer
      de répertoire courant. <programlisting width="80">
<emphasis>EXEMPLES :</emphasis>

$ pwd                                                                           
/home/pascal/lecture

$ cd /usr
$ pwd
/usr

$ cd local/bin
$ pwd 
/usr/local/bin

</programlisting> Sans argument, la commande <command>cd</command> nous ramène
      dans notre répertoire de domiciliation (ce qui est équivalent à  la
      séquence <computeroutput>cd ~</computeroutput>, <abbrev>c.f.</abbrev>
      shell). <programlisting width="80">
<emphasis>EXEMPLE :</emphasis>

$ pwd                                                                           
/usr/local/bin

$ cd
$ pwd
/home/pascal

</programlisting></para>
    </sect2>

    <sect2>
      <title>Gérer les répertoires : <command>mkdir</command>,
      <command>rmdir</command></title>

      <formalpara>
        <title><command>mkdir</command></title>

        <para>Cette commande permet de créer de nouveau(x) répertoire(s)
        <programlisting width="80">
<emphasis>EXEMPLE :</emphasis>

$ ls -F                                                                         
bin/  mytmp@  test/  tmp/
$ mkdir rep1 rep2 rep3 rep4
$ ls -F
bin/  mytmp@  rep1/  rep2/  rep3/  rep4/  test/  tmp/

</programlisting> L'option <option>-p</option> de la commande
        <command>mkdir</command> permet de créer une hiérarchie en une seule
        opération, dans l'exemple ci-après, on crée un répertoire
        (<filename>rep5</filename>) contenant un répertoire
        (<filename>facile</filename>) contenant ... : <programlisting
        width="80">
<emphasis>EXEMPLE :</emphasis>

$ mkdir -p rep5/facile/a/faire                                                  
$ ls -R rep5
ls -FR rep5
rep5:
facile/

rep5/facile:
a/

rep5/facile/a:
faire/

rep5/facile/a/faire:

</programlisting></para>
      </formalpara>

      <formalpara>
        <title><command>rmdir</command></title>

        <para>Cette commande permet de supprimer un répertoire vide. Supprimer
        un répertoire revient explicitement à  supprimer les objets qu'il
        contient. C'est logique, mais inefficace si la hiérarchie à  supprimer
        contient beaucoup d'objets, <abbrev>c.f.</abbrev> la section consacrée
        à  la commande <command>rm</command> pour une méthode radicalement         efficace.</para>
      </formalpara>

      <simplesect>
        <title>Illustration - Répertoires</title>

        <para><orderedlist inheritnum="inherit" numeration="lowerroman"
            spacing="compact">
            <listitem>
              <para>Créer dans votre répertoire de domiciliation le répertoire
              <filename>~/elementBase</filename>/</para>
            </listitem>

            <listitem>
              <para>Créer dans votre répertoire de domiciliation le répertoire
              <filename>~/elementBase/part1/</filename> en utilisant l'option
              <option>-p</option></para>
            </listitem>

            <listitem>
              <para> à quelle condition est-ce que la ligne de commande
              <computeroutput>mkdir
              ~elementBase/part1/exo1/com</computeroutput> peut fonctionner et
              créer effectivement ce sous-répertoire ?</para>
            </listitem>

            <listitem>
              <para>Vous voulez créer à  la fois un répertoire
              <filename>~/elementBase/part1/exo1/dir1/</filename> et un sous
              répertoire <filename>~/elementBase/part1/exo1/dir2</filename> .
              Quelle option faut-il utiliser pour que : 1. Si
              <filename>~/elementBase/part1/exo1</filename> n'existe pas, le
              répertoire et son sous-répertoire soient créés; 2. Si
              <filename>~/elementBase/part1/exo1</filename> existe déjà , le
              sous-répertoire <filename>dir1/</filename> soit créé, sans
              message d'erreur.</para>
            </listitem>
          </orderedlist></para>
      </simplesect>
    </sect2>

    <sect2>
      <title>.. et .</title>

      <para>La désignation <quote><emphasis role="bold">..</emphasis></quote>
      désigne le répertoire père du répertoire courant. <programlisting
      width="80">
<emphasis>EXEMPLES :</emphasis>

$ pwd                                                                           
/usr/local/bin

$ cd ..
$ pwd
/usr/local

$ cd ../sbin
$ pwd
/usr/sbin

</programlisting> <important>
          <para>Sous <emphasis>Unix</emphasis>, une commande est séparée de
          ces arguments par les caractères d'espacement. Ainsi
          <computeroutput>cd..</computeroutput> n'a pas de sens ! Il faut
          écrire <computeroutput>cd ..</computeroutput>, noter bien l'espace
          séparateur.</para>
        </important></para>

      <para>La désignation <quote><emphasis role="bold">.</emphasis></quote>
      désigne le répertoire courant, c'est donc une auto-référence. Ainsi
      l'opération suivante, ne modifie nullement le répertoire courant :
      <programlisting width="80">
<emphasis>EXEMPLE :</emphasis>

$ pwd                                                                           
/usr/sbin
$ cd .
$ pwd
/usr/sbin                                                                  

</programlisting> Cette désignation est souvent utilisée pour exécuter un
      programme situé dans le répertoire courant, <abbrev>i.e.</abbrev> hors
      des localisations traditionnelles. <programlisting width="80">
<emphasis>EXEMPLE :</emphasis>

$ pwd                                                                           
/usr/sbin
$ cd
$ pwd
/home/pascal
$ cd mybin
$ pwd 
/home/pascal/mybin
$ ./myprog
...
exécution de myprog
...                                                                

</programlisting></para>
    </sect2>

    <sect2>
      <title><command>ls (1)</command></title>

      <para>Cette commande (situé traditionnellement dans
      <filename>/bin</filename>), permet de lister le contenu d'un répertoire.
      Elle contient nombre d'options permettant d'avoir beaucoup de détails.
      <programlisting width="80">
<emphasis>EXEMPLE :</emphasis>

$ cd /usr/local
$ ls 
Acrobat5            bin               lib                 ports            work 
GNUstep             distfiles         libdata             proj             www
OpenOffice.org1.0   etc               libexec             sbin
OpenOffice.org1.0.3 include           linux-sun-jdk1.3.1  share
ant                 info              man                 src
apps                jdk1.3.1          pgsql               sup

</programlisting> L'option <option>-a</option> permet de lister en plus les
      <foreignphrase>dotfiles</foreignphrase>, <abbrev>i.e.</abbrev> les
      fichiers cachés qui commencent toujours par un point (dans leur nom),
      ici nous obtenons en plus les entrées spéciales <quote>.</quote> et
      <quote>..</quote> : <programlisting width="80">
<emphasis>EXEMPLE :</emphasis>

$ pwd
/usr/local
$ ls -a
.                   ant               info                man              src  
..                  apps              jdk1.3.1            pgsql            sup
Acrobat5            bin               lib                 ports            work
GNUstep             distfiles         libdata             proj             www
OpenOffice.org1.0   etc               libexec             sbin
OpenOffice.org1.0.3 include           linux-sun-jdk1.3.1  share

</programlisting> L'option <option>-l</option> permet de lister au format long
      le répertoire ou le fichier qui lui est éventuellement passé en
      argument. <programlisting width="80">
<emphasis>EXEMPLES :</emphasis>

$ ls -l /usr                                                                    
total 41
drwxr-xr-x  13 root  wheel   512 May 25 13:21 X11R6
drwxr-xr-x   2 root  wheel  7168 May 24 10:19 bin
drwxr-xr-x   3 root  wheel   512 Jan  8  2003 compat
drwxr-xr-x   3 root  wheel   512 Jan  6  2003 games
drwxr-xr-x  41 root  wheel  3584 May 24 10:18 include
drwxr-xr-x   4 root  wheel  6144 May 24 10:19 lib
drwxr-xr-x   9 root  wheel   512 Oct  9  2002 libdata
drwxr-xr-x   8 root  wheel  1536 May 24 10:19 libexec
drwxr-xr-x  28 root  wheel   512 Jul 10 08:23 local
drwxrwxrwt  44 root  wheel  9216 May 24 14:48 lost+found
drwxr-xr-x   3 root  wheel   512 May 24 09:23 obj
drwxr-xr-x   2 root  wheel  4096 May 24 10:19 sbin
drwxr-xr-x  27 root  wheel   512 May 24 10:17 share
drwxr-xr-x  21 root  wheel   512 May 12 22:02 src
drwxr-xr-x   3 root  wheel   512 Jan  8  2003 sup

$ ls -l /etc/passwd
-rw-r--r--  1 root  wheel  1527 Aug  7 01:50 /etc/passwd

</programlisting> Sans trop rentrer dans les détails, notons que les listings
      précédents, sont structurés en sept colonnes. De la gauche vers la
      droite, on trouve en première colonne les permissions sur l'objet, en
      seconde colonne le nombre de liens sur l'objet, puis en troisième et
      quatrième le propriétaire et le groupe de l'objet, en cinquième la
      taille en octet, en sixième la date de dernière modification
      (<foreignphrase>mtime</foreignphrase>) de l'objet. Enfin, la dernière
      colonne donne le nom de l'objet.</para>

      <!-- ========== added - Kurzweg 15/02/2006========== -->

      <para>Nous examinerons plus tard la première colonne en détail, celle
      qui présente en détail les permisssions sur le'objet, mais nous pouvons
      déjà  décomposer ces informations en quatre groupes <computeroutput> -
      rwx rwx rwx</computeroutput>. Le premier sous-groupe décrit le type de
      fichier : un fichier ordinaire est représenté par un <quote>-</quote>,
      et les répertoires par <quote>d</quote>. La liste suivante présente les
      différents types de fichiers exprimés dans le premier sous-groupe :
      <itemizedlist mark="" spacing="compact">
          <listitem>
            <para><quote>-</quote> : Fichier ordinaire</para>
          </listitem>

          <listitem>
            <para><quote>b</quote> : Fichier spécial en mode bloc</para>f
          </listitem>

          <listitem>
            <para><quote>c</quote> : Fichier spécial en mode caractère</para>
          </listitem>

          <listitem>
            <para><quote>d</quote> : Répertoire</para>
          </listitem>

          <listitem>
            <para><quote>l</quote> : lien symbolique</para>
          </listitem>

          <listitem>
            <para><quote>p</quote> : tube nommé (pipe)</para>
          </listitem>
        </itemizedlist></para>

      <para>Il est possible de lister le/les répertoires sans leur(s)
      contenu(s) (option <option>-d</option>). Il est évidement possible de
      combiner les options : <programlisting width="80">
<emphasis>EXEMPLE :</emphasis>

$ ls -ld /usr /usr/bin /usr/sbin                                                
drwxr-xr-x  17 root  wheel   512 Jan  8  2003 /usr
drwxr-xr-x   2 root  wheel  7168 May 24 10:19 /usr/bin
drwxr-xr-x   2 root  wheel  4096 May 24 10:19 /usr/sbin

</programlisting> De manière symétrique, on peut vouloir voir l'ensemble des
      informations d'un répertoire donné, <abbrev>i.e.</abbrev> l'ensemble des
      informations sur les répertoires et sous répertoires qu'il contient
      (parcours récursif) avec l'option (<option>-R</option>). Attention cela
      peut être volumineux !</para>

      <para>Essayez-le dans votre <varname>HOME</varname>, puis dans
      <filename>/home</filename>.</para>

      <simplesect>
        <title>Illustration - ls</title>

        <para><orderedlist inheritnum="inherit" numeration="lowerroman"
            spacing="compact">
            <listitem>
              <para>Listez le répertoire au format long :
              <filename>~/elementBase/part1/</filename> et interprétez le
              résultat</para>
            </listitem>

            <listitem>
              <para>Créez le fichier
              <filename>~/elementBase/part1/fic1</filename> contenant une
              phrase de votre choix.</para>
            </listitem>

            <listitem>
              <para>Lister de nouveau le répertoire - Interprétez le résultat.
              Que représente <filename>total ? </filename></para>
            </listitem>

            <listitem>
              <para>Créez un deuxième fichier, puis un sous répertoire et
              notez les changements.</para>
            </listitem>
          </orderedlist></para>
      </simplesect>
    </sect2>

    <sect2>
      <title>Notion d'inode</title>

      <para>Tout est fichier sous <emphasis>Unix</emphasis> (<quote>credo
      <emphasis>Unix</emphasis>ien</quote>, un répertoire est donc un fichier)
      et chaque fichier se voit attribuer un index unique appelé
      <foreignphrase>inode [index node]</foreignphrase>. Informellement, un
      <foreignphrase>inode</foreignphrase> est une structure de données qui
      décrit le contenu d'un fichier à  l'exception notable de son nom (sa
      désignation). Un fichier peut ainsi avoir plusieurs désignations
      différentes, lesquelles sont stockées dans les répertoires<footnote>
          <para>Tout aussi informellement, un répertoire est une liste de
          couple {<foreignphrase>inode</foreignphrase> de l'objet, nom de
          l'objet}.</para>
        </footnote>. La liste des <foreignphrase>inodes</foreignphrase> d'un
      répertoire donné est obtenue avec la commande <computeroutput>ls -i
      &lt;repertoire&gt;</computeroutput>. On peut évidemment combiner les
      options : <programlisting width="80">
<emphasis>EXEMPLE :</emphasis>

$ ls -ila /usr/X11R6/libexec                                                    
total 137
3984118 drwxr-xr-x   4 root  wheel    512 Jun 22 19:11 .
3928896 drwxr-xr-x  13 root  wheel    512 May 25 13:21 ..
3983621 -r-xr-xr-x   1 root  wheel   8296 Jun 22 16:40 gconf-sanity-check-2
3983619 -r-xr-xr-x   1 root  wheel  45752 Jun 22 16:40 gconfd-2
4005734 drwxr-xr-x   3 root  wheel    512 May 25 15:48 gkrellm
3983624 -r-xr-xr-x   1 root  wheel   5112 Jun 22 19:04 gnome2-db2html
3983625 -r-xr-xr-x   1 root  wheel  21884 Jun 22 19:04 gnome2-info2html
3983623 -r-xr-xr-x   1 root  wheel  43848 Jun 22 19:04 gnome2-man2html
3983626 -r-xr-xr-x   1 root  wheel   8564 Jun 22 19:11 gnome_segv2
4017439 drwxr-xr-x   2 root  wheel    512 May 29 15:36 sawfish

</programlisting> Observons que le répertoire
      <filename>/usr/X11R6/libexec</filename> possède
      l'<foreignphrase>inode</foreignphrase> 3984118 et qu'il est réréfencé 4
      fois (<abbrev>i.e.</abbrev> bien qu'existant en un seul endroit cet
      <foreignphrase>inode</foreignphrase> possède plusieurs références).
      Quelles sont-elles (<abbrev>c.f.</abbrev> ci-après) ? <programlisting
      width="80">
<emphasis>EXEMPLE :</emphasis>

$ ls -idl /usr/X11R6/libexec /usr/X11R6/libexec/. /usr/X11R6/libexec/gkrellm/.. /
usr/X11R6/libexec/sawfish/..
3984118 drwxr-xr-x  4 root  wheel  512 Jun 22 19:11 /usr/X11R6/libexec
3984118 drwxr-xr-x  4 root  wheel  512 Jun 22 19:11 /usr/X11R6/libexec/.
3984118 drwxr-xr-x  4 root  wheel  512 Jun 22 19:11 /usr/X11R6/libexec/gkrellm/..
3984118 drwxr-xr-x  4 root  wheel  512 Jun 22 19:11 /usr/X11R6/libexec/sawfish/..

</programlisting> Puisque <quote>..</quote> est une référence au répertoire
      père du répertoire courant,
      <filename>/usr/X11R6/libexec/gkrellm/..</filename> et
      <filename>/usr/X11R6/libexec/sawfish/..</filename> sont bien deux
      désignations différentes du même objet (à  savoir
      <filename>/usr/X11R6/libexec</filename>, qui est aussi désigné par
      <filename>/usr/X11R6/libexec/</filename>).</para>
    </sect2>

    <sect2>
      <title>Liens durs (<command>ln (1)</command>)</title>

      <para>La désignation d'un <foreignphrase>inode</foreignphrase> est
      encore appelée : <emphasis>lien
      [<foreignphrase>link</foreignphrase>]</emphasis>. Un
      <foreignphrase>inode</foreignphrase> peut posséder plusieurs
      désignations qu'on appelle <emphasis>liens durs [<foreignphrase>hard
      links</foreignphrase>]</emphasis>.
      L'<foreignphrase>inode</foreignphrase> ainsi multi-référencé existe au
      sein du <foreignphrase>filesystem</foreignphrase> tant qu'il reste un
      lien dur le référençant. Pour créer un <emphasis>lien dur</emphasis>, on
      utilise la commande <command>ln</command> : <programlisting width="80">
<emphasis>EXEMPLE :</emphasis>

$ touch toto                                                                    
$ ls -i
  96770 toto
$ ln toto titi         # ln &lt;src&gt; &lt;dst&gt;
$ ls -i
  96770 titi    96770 toto

</programlisting> Limitations classiques des <emphasis>liens durs</emphasis> :
      <itemizedlist spacing="normal">
          <listitem>
            <para>On ne peut créer des liens durs que sur des fichiers
            (réguliers, caractère, bloc, socket, <foreignphrase>named
            pipe</foreignphrase>...) et non sur des (fichiers)
            répertoires<footnote>
                <para><emphasis role="bold">.</emphasis> et <emphasis
                role="bold">..</emphasis> sont des liens durs sur des
                répertoires, mais aucun utilisateur, pas même le
                <emphasis>super</emphasis>-utlisateur
                <emphasis>root</emphasis> ne peut créer de tels liens.</para>
              </footnote>.</para>
          </listitem>

          <listitem>
            <para>Les liens ne traversent pas les limites d'un
            <foreignphrase>filesystem</foreignphrase><footnote>
                <para>Au sens <emphasis>Unix</emphasis> un
                <foreignphrase>filesystem</foreignphrase> est une collection
                de fichiers. Il est organisé hiérarchiquement à  l'aide de
                répertoires et se restreint en général à  un type de support
                physique, typiquement le disque dur. Un
                <foreignphrase>filesystem</foreignphrase> est un aussi un
                espace de nommage et de contrôle d'accès aux fichiers qu'il
                contient.</para>
              </footnote>.</para>
          </listitem>
        </itemizedlist></para>

      <para>Enfin, puisque chaque désignation <quote>pointe</quote> (ou
      référence) le même inode (objet) et que les droits d'accès sont stockés
      dans l'inode, les différentes désignations (liens durs) ont les mêmes
      droits d'accès<footnote>
          <para>C'est quasi incorrect, en fait, la désignation ne possède
          aucun droit !</para>
        </footnote>.</para>

      <simplesect>
        <title>Illustration - liens durs</title>

        <para><orderedlist inheritnum="inherit" numeration="lowerroman"
            spacing="compact">
            <listitem>
              <para>Créez le répertoire
              <filename>~/elementBase/part1/links/</filename>.</para>
            </listitem>

            <listitem>
              <para>Créez le lien
              <filename>~/elementBase/part1/links/link1</filename> référençant
              le fichier <filename>~/elementBase/part1/fic1</filename> créé
              précédemment.</para>
            </listitem>

            <listitem>
              <para>Comparez les fichiers
              <filename>~/elementBase/part1/links/link1</filename> et
              <filename>~/elementBase/part1/fic1</filename> (inode, taille,
              résultat à  l'affichage)</para>
            </listitem>

            <listitem>
              <para>Supprimer<filename>~/elementBase/part1/fic1</filename> Que
              constatez vous ?</para>
            </listitem>
          </orderedlist></para>
      </simplesect>
    </sect2>

    <sect2>
      <title>Liens symboliques (<command>ln
      <option>-s</option></command>)</title>

      <para>Les limitations sur les <emphasis>liens durs
      [<foreignphrase>symbolic links</foreignphrase>]</emphasis> ont conduit à 
      l'élaboration d'un nouveau type de fichier dit <emphasis>lien
      symbolique</emphasis>. Un tel (type de) fichier se refère à  un autre par
      le nom plutôt que par l'<foreignphrase>inode</foreignphrase>, en fait le
      contenu de ce fichier est un chemin absolu ou relatif qui conduit au
      fichier référencé. Pour créer un <emphasis>lien symbolique</emphasis>,
      on utilise la commande <command>ln <option>-s</option></command> :
      <programlisting width="80">
<emphasis>EXEMPLE :</emphasis>

$ ln -s ~/tmp mytmp     # création d'un lien symb. sur le répertoire ~/tmp      
$ ll                    # utilisation de l'alias 
total 8
lrwxrwxrwx    1 pascal   gnu           16 Aug 14 13:14 mytmp -&gt; /home/pascal/tmp
drwx------    2 pascal   gnu         4096 Aug 14 09:45 test
drwx------    2 pascal   gnu         4096 Aug 14 13:14 tmp
$ cd mytmp ; pwd                   # vérification
/home/pascal/mytmp      

$ ll -i . ~/tmp         # contenu ~/mytmp qui est le contenu de ~/tmp
.:
total 1
  96770 -rw-------    1 pascal   gnu            24 Aug 14 13:19 toto
  96771 lrwxrwxrwx    1 pascal   gnu             4 Aug 14 11:14 tutu -&gt; toto

/home/pascal/tmp:
total 1
  96770 -rw-------    1 pascal   gnu            24 Aug 14 13:19 toto
  96771 lrwxrwxrwx    1 pascal   gnu             4 Aug 14 11:14 tutu -&gt; toto

</programlisting> Remarques : <itemizedlist spacing="normal">
          <listitem>
            <para>un lien symbolique est dénoté par un <emphasis
            role="bold">l</emphasis> dans le listage au format long
            (<command>ls <option>-l</option></command> ou son alias
            <command>ll</command>),</para>
          </listitem>

          <listitem>
            <para>la taille d'un lien symbolique (exprimée en octet) est la
            taille nécessaire au stockage du chemin d'accès (relatif ou
            absolu) à  l'objet référencé (dans l'exemple précédent 4 octets
            pour la désignation relative <quote>toto</quote>),</para>
          </listitem>

          <listitem>
            <para>un lien symbolique peut référencer un fichier régulier, un
            répertoire, un fichier en mode bloc ou caractère...</para>
          </listitem>

          <listitem>
            <para>puisqu'un lien symbolique s'appuie sur la notion de chemin
            (et non d'<foreignphrase>inode</foreignphrase>) il est possible
            d'en créer sur un objet d'un <emphasis>filesystem</emphasis>
            différent.</para>
          </listitem>

          <listitem>
            <para>Les droits d'accès au lien symbolique sont, logiquement, les
            droits d'accès à  l'objet référencé, ainsi sous
            <emphasis>GNU/Linux</emphasis> le <quote>lrwxrwxrwx</quote> qui
            apparaît lors d'un listage au format long n'a pas de
            signification, tandis que sous <emphasis>xBSD</emphasis> les
            droits qui s'affichent sont hérités de la valeur de
            l'<emphasis>umask</emphasis> de l'utilisateur (uid) qui créé le
            lien, cette valeur n'est pas mise à  jour si les droits de l'objet
            référencé sont modifiés !</para>
          </listitem>
        </itemizedlist></para>

      <simplesect>
        <title>Illustration - liens symboliques</title>

        <para><orderedlist inheritnum="inherit" numeration="lowerroman"
            spacing="compact">
            <listitem>
              <para>Créez le lien symbolique
              <filename>~/elementBase/part1/links/link2</filename> référençant
              le fichier <filename>~/elementBase/part1/fic2</filename> créé
              précédemment.</para>
            </listitem>

            <listitem>
              <para>Comparez les fichiers
              <filename>~/elementBase/part1/links/link2</filename> et
              <filename>~/elementBase/part1/fic2</filename> . (inode, taille,
              résultat à  l'affichage)</para>
            </listitem>

            <listitem>
              <para>Supprimer <filename>~/elementBase/part1/fic2</filename> Que
              constatez vous ?</para>
            </listitem>
          </orderedlist></para>
      </simplesect>
    </sect2>

    <sect2>
      <title>Manipuler les fichiers : <command>file</command>,
      <command>cp</command>, <command>mv</command>,
      <command>rm</command></title>

      <formalpara>
        <title><command>file (1)</command></title>

        <para>Cette commande tente de déterminer le type du fichier qui lui
        est passé en argument. <programlisting width="80">
<emphasis>EXEMPLES :</emphasis>

$ file ~/tmp/toto
/home/pascal/tmp/toto: ASCII text

$ file ~/test/C/bin/_crypt
_crypt: ELF 32-bit LSB executable, Intel 80386, version 1 (SYSV), for GNU/Linux 
2.0.0, dynamically linked (uses shared libs), not stripped

$ file ~/test/C/src/_crypt.c
/home/pascal/test/C/src/_crypt.c: ISO-8859 C program text

$ file ~/bin/_backup
/home/pascal/bin/_backup: C shell script text executable

$ file /bin/rm
/bin/rm: ELF 32-bit LSB executable, Intel 80386, version 1 (FreeBSD), for FreeBS
D 4.8, statically linked, stripped

$ file /usr/local/bin/xemacs
/usr/local/bin/xemacs: symbolic link to xemacs-21.1.14

</programlisting></para>
      </formalpara>

      <formalpara>
        <title><command>cp (1)</command></title>

        <para>Cette commande permet de copier un fichier existant.
        <programlisting width="80">
<emphasis>EXEMPLE :</emphasis>

$ pwd                                   # oà¹ suis-je ?
/home/pascal/tmp
$ ls -i                                 # quels sont les "objets" ?
  96771 bookmarks.html                  # 1 "objet"
$ cp bookmarks.html bookmarks.html.SAV  # en faire une copie de sauvegarde      
$ ls -i                                 # "objets" physiquement différents ?
  96771 bookmarks.html    96770 bookmarks.html.SAV

</programlisting> <note>
            <para><itemizedlist spacing="normal">
                <listitem>
                  <para>La commande <command>cp</command> créée bien un objet
                  différent puisque les deux fichiers ont des
                  <foreignphrase>inodes</foreignphrase> différents.</para>
                </listitem>

                <listitem>
                  <para>Noter le format : <command>cp</command> &lt;src&gt;
                  &lt;dst&gt;, si &lt;dst&gt; existe il est écrasé par
                  défaut.</para>
                </listitem>
              </itemizedlist></para>
          </note></para>
      </formalpara>

      <formalpara>
        <title><command>mv (1)</command></title>

        <para>Cette commande permet de déplacer/renommer un fichier existant
        dans l'arborescence. Un déplacement ne change pas
        l'<foreignphrase>inode</foreignphrase> <emphasis>tant que l'on reste
        dans le même <foreignphrase>filesystem</foreignphrase></emphasis>,
        mais sa localisation dans l'arborescence <abbrev>i.e.</abbrev> sa
        désignation (sa référence ou encore son nom). <programlisting
        width="80">
<emphasis>EXEMPLES :</emphasis>

$ pwd                        # oà¹ suis-je ?
/home/pascal/tmp
$ ls -i                      # inodes des "objets"
  96771 bookmarks.html    96770 bookmarks.html.SAV
$ mv bookmarks.html ~/test   # déplacement de bookmarks.html dans le rép. ~/test
$ ls -i . ~/test             # l'inode de bookmarks.html est toujours 96771
.:
  96770 bookmarks.html.SAV

/home/pascal/test:
  96771 bookmarks.html

$ mv ~/test/bookmarks.html /tmp  # changement de filesystem
$ ls -i /tmp/bookmarks.html
     14 /tmp/bookmarks.html

</programlisting> Rappel : <filename>/tmp</filename> réside sur une partition
        séparée, or l'unicité des numéros
        d'<foreignphrase>inodes</foreignphrase> est assuré uniquement dans un
        <foreignphrase>filesystem</foreignphrase> donné.<!-- N O T E : j'utilise partition et filesystem comme des synonymes, cela reste une approx. --></para>
      </formalpara>

      <formalpara id="rm">
        <title><command>rm</command></title>

        <para>Cette commande permet d'enlever les objets d'un
        <foreignphrase>filesystem</foreignphrase>. <programlisting width="80">
<emphasis>EXEMPLE :</emphasis>

$ pwd
/home/pascal
$ ls -F
bin/  file.txt  file.txt~  test/  titi  titi.o  titi~  tmp/  tootoo  toto  toto.
o  toto~
$ rm titi
/bin/rm: remove regular file `titi'? y
$ ls -F     # plus de "titi"
bin/  file.txt  file.txt~  test/  titi.o  titi~  tmp/  tootoo  toto  toto.o  tot
o~
$ rm *      # effacer tous les fichiers !
/bin/rm: remove directory `bin'? y
/bin/rm: cannot remove directory `bin': Is a directory
/bin/rm: remove regular file `file.txt'? y
/bin/rm: remove regular file `file.txt~'? y
/bin/rm: remove directory `test'? y
/bin/rm: cannot remove directory `test': Is a directory
/bin/rm: remove regular empty file `titi.o'? y
/bin/rm: remove regular file `titi~'? y
/bin/rm: remove directory `tmp'?^C
$

</programlisting> <note>
            <para><itemizedlist spacing="normal">
                <listitem>
                  <para>Dans l'exemple, il y a demande de confirmation avant
                  d'enlever l'objet. Cela est dû au fait que nous avons défini
                  un alias sur rm, qui active l'option <option>-i</option>
                  (pour interactif). Le comportement par défaut de
                  <command>rm</command> est le comportement classique des
                  commandes <emphasis>Unix</emphasis> : être silencieux quand
                  il n'y a rien de spécial à  signaler<footnote>
                      <para><foreignphrase>Rule of silence : when a program
                      has nothing surprising to say, it should say
                      nothing.</foreignphrase></para>
                    </footnote> .</para>
                </listitem>

                <listitem>
                  <para>Le métacaractère <quote>*</quote> désigne tous les
                  objets (<abbrev>i.e.</abbrev> tous les fichiers).</para>
                </listitem>

                <listitem>
                  <para>Sans argument(s) spécifique(s) la commande
                  <command>rm</command> tente d'effacer les fichiers qui ne
                  sont pas des répertoires.</para>
                </listitem>
              </itemizedlist></para>
          </note> <emphasis role="bold">Effacer un répertoire : </emphasis> un
        répertoire n'est autre qu'un fichier contenant une liste de couple
        &lt;désignation, <foreignphrase>inode</foreignphrase>&gt;. Effacer un
        répertoire revient à  effacer son contenu (récursivement) puis le
        répertoire lui-même. Pour effectuer une telle action on utilise
        l'option <option>-r</option> ou l'option synonyme <option>-R</option>
        de la commande <command>rm</command>. Compte tenu de l'alias existant,
        la séquence <computeroutput>rm -r ~/tmp</computeroutput> (dont la
        sémantique est : <quote>effacer l'arborescence désignée par
        <filename>~/tmp</filename></quote>) va demander confirmation de
        l'effacement de chacun des objets. Si on est sûr de ce que l'on fait,
        on utilisera plutôt la commande suivante <computeroutput>rm -rf
        ~/tmp</computeroutput> (dont la sémantique est : <quote>effacer
        l'arborescence désignée par <filename>~/tmp</filename>, sans me poser
        de questions</quote>), <emphasis>attention c'est radical !</emphasis>.
        <programlisting width="80">
<emphasis>EXEMPLE :</emphasis>

$ pwd                # oà¹ suis-je ?
/home/pascal

$ ls -F              # quel est le contenu ?
bin/  test/  tmp/  tootoo  toto  toto.o  toto~

$ ls -lR ~/tmp       # quel est le contenu de ~/tmp ? 
total 20             # 2 fichiers réguliers
-rw-------    1 pascal   gnu         20341 Aug 14 09:18 bookmarks.html.SAV      
-rw-------    1 pascal   gnu             0 Aug 14 09:56 toto

$ rm -rf ~/tmp       # "supprimer" le répertoire ~/tmp, sans confirmation
$ ls -F              # ~/tmp n'existe plus
bin/  test/  tootoo  toto  toto.o  toto~

</programlisting></para>
      </formalpara>

      <simplesect>
        <title>Illustration - Manipulation de fichiers</title>

        <para><orderedlist inheritnum="inherit" numeration="lowerroman"
            spacing="compact">
            <listitem>
              <para>Copiez <filename>~/elementBase/part1/links/link2</filename>
              vers le fichier <filename>~/elementBase/part1/fic2</filename>
              créé précédemment.</para>
            </listitem>

            <listitem>
              <para>Comparez les fichiers
              <filename>~/elementBase/part1/links/link2</filename> et
              <filename>~/elementBase/part1/fic2</filename> . (inode, taille,
              résultat à  l'affichage)</para>
            </listitem>

            <listitem>
              <para>Créez en une commande les fichiers
              <filename>~/elementBase/part1/fic3 </filename>et
              <filename>~/elementBase/part1/fic4</filename> . Déplacez tous les
              fichiers commençant par <filename>fic</filename> vers le
              répertoire en une seule commande (utilisation des méta -
              caractères)</para>
            </listitem>
          </orderedlist></para>
      </simplesect>
    </sect2>

    <sect2>
      <title><command>who</command>, <command>logname</command>,
      <command>whoami</command>, <command>hostname</command></title>

      <formalpara>
        <title><command>who (1)</command></title>

        <para>Permet de connaître qui travaille actuellement sur cette
        machine. <programlisting width="80">
<emphasis>EXEMPLE :</emphasis>

$ who                                                                           
guest            ttyv1    Aug 13 11:39 
pascal           ttyp0    Aug 10 11:26 (:0.0)
pascal           ttyp1    Aug 13 11:39 (:0.0)
pascal           ttyp2    Aug 11 12:01 (:0.0)
pascal           ttyp3    Aug  7 08:15 (:0.0)
foo              ttyp4    Aug 13 11:39 (Euler)
pascal           ttyp5    Aug 11 12:00 (:0.0)
pascal           ttyp6    Aug  9 08:32 (:0.0)

</programlisting> Indique ici : <itemizedlist spacing="normal">
            <listitem>
              <para>que l'utilisateur <emphasis>guest</emphasis> est connecté
              sur le premier terminal non graphique (ttyv1).</para>
            </listitem>

            <listitem>
              <para>que l'utilisateur <emphasis>pascal</emphasis> est connecté
              sur 6 terminaux (en interface graphique, la notation :0.0 de la
              dernière colonne indiquant le
              <foreignphrase>display</foreignphrase> graphique.</para>
            </listitem>

            <listitem>
              <para>enfin, que l'utilisateur <emphasis>foo</emphasis> est
              connecté sur le terminal ttyp4, depuis la machine Euler (session
              distante ssh, par exemple).</para>
            </listitem>
          </itemizedlist></para>
      </formalpara>

      <formalpara>
        <title><command>logname (1)</command> et <command>whoami
        (1)</command></title>

        <para>Sans argument ces deux commandes donnent le nom de connexion de
        l'utilisateur courant. <programlisting width="80">
<emphasis>EXEMPLE :</emphasis>

$ whoami                                                                        
pascal
$ logname
pascal

</programlisting></para>
      </formalpara>

      <formalpara>
        <title><command>hostname (1)</command></title>

        <para>Affiche le nom de la machine courante. <programlisting
        width="80">
<emphasis>EXEMPLE :</emphasis>

$ hostname -s # nom court : xBSD                                                
Godel

$ hostname # GNU/Linux                                                          
tux

</programlisting></para>
      </formalpara>
    </sect2>

    <sect2>
      <title><command>id</command>, <command>tty</command>,
      <command>printenv</command></title>

      <formalpara>
        <title><command>id (1)</command></title>

        <para>Affiche l'identifiant de l'utilisateur (uid), son identifiant de
        groupe primaire (gid), les identifiants des groupes secondaires, ainsi
        que les nom associés. <programlisting width="80">
<emphasis>EXEMPLE :</emphasis>

$ id                                                                            
uid=666(pascal) gid=666(gnu) groups=666(gnu), 0(wheel), 5(operator), 88(mysql), 
668(cvs), 70(pgsql)

</programlisting></para>
      </formalpara>

      <formalpara>
        <title><command>tty (1)</command></title>

        <para>Affiche le nom du terminal courant <programlisting width="80">
<emphasis>EXEMPLE :</emphasis>

$ tty                                                                           
/dev/ttyp7

</programlisting></para>
      </formalpara>

      <formalpara>
        <title><command>printenv (1)</command></title>

        <para>Affiche toute ou partie de l'environnement courant.
        <programlisting width="80">
<emphasis>EXEMPLE :</emphasis>

$ printenv # FreeBSD                                                            
SSH_AGENT=/usr/bin/ssh-agent
USER=pascal
MAIL=/var/mail/pascal
HOME=/home/pascal
SSH_ASKPASS=/usr/X11R6/bin/ssh-askpass
LOGNAME=pascal
BLOCKSIZE=K
PATH=/usr/local/sbin:/usr/local/bin:/sbin:/bin:/usr/sbin:/usr/bin:/usr/X11R6/bin
:/home/pascal/bin
DISPLAY=:0.0
SHELL=/bin/tcsh
FTP_PASSIVE_MODE=YES
SSH_AUTH_SOCK=/tmp/ssh-isrTtwab/agent.463
SSH_AGENT_PID=478
WMAKER_BIN_NAME=/usr/X11R6/bin/wmaker
WRASTER_COLOR_RESOLUTION0=4
IFS=    

ETERM_THEME_ROOT=/usr/X11R6/share/Eterm/themes/Eterm
ETERM_USER_ROOT=/home/pascal/.Eterm
COLORFGBG=default
WINDOWID=54526015
TERM=xterm-color
COLORTERM=rxvt
COLORTERM_BCE=Eterm
ETERM_VERSION=0.9.2
HOSTTYPE=FreeBSD
VENDOR=amd
OSTYPE=FreeBSD
MACHTYPE=i386
SHLVL=1
PWD=/home/pascal/bin
GROUP=gnu
HOST=Godel.corto.home
color=1
colorcat=1
LC_CTYPE=fr_FR.ISO8859-15
PAGER=less
MOZILLA_HOME=/usr/X11R6/bin/mozilla
EDITOR=emacs
CPUTYPE=k7
TEXEDIT=emacs
LSCOLORS=EhGxbxcxBxdxHBhbafhCad
CLICOLOR=1
CLICOLOR_FORCE=1
RSYNC_RSH=/usr/bin/ssh
CVSROOT=/home/cvsroot

$ printenv  # GNU/Linux
LC_PAPER=a4
TERM=xterm-color
SHELL=/bin/bash
SSH_CLIENT=192.168.200.2 3878 22
SSH_TTY=/dev/pts/0
USER=pascal
LS_COLORS=no=00:fi=00:di=01;34:ln=01;36:pi=40;33:so=01;35:do=01;35:bd=40;33;01:c
d=40;33;01:or=40;31;01:ex=01;32:*.tar=01;31:*.tgz=01;31:*.arj=01;31:*.taz=01;31:
*.lzh=01;31:*.zip=01;31:*.z=01;31:*.Z=01;31:*.gz=01;31:*.bz2=01;31:*.deb=01;31:*
.rpm=01;31:*.jar=01;31:*.jpg=01;35:*.jpeg=01;35:*.gif=01;35:*.bmp=01;35:*.pbm=01
;35:*.pgm=01;35:*.ppm=01;35:*.tga=01;35:*.xbm=01;35:*.xpm=01;35:*.tif=01;35:*.ti
ff=01;35:*.png=01;35:*.mpg=01;35:*.mpeg=01;35:*.avi=01;35:*.fli=01;35:*.gl=01;35
:*.dl=01;35:*.xcf=01;35:*.xwd=01;35:*.ogg=01;35:*.mp3=01;35:*.wav=01;35:
PAGER=less
MAIL=/var/mail/pascal
PATH=/usr/local/bin:/usr/bin:/bin:/usr/bin/X11:/usr/games
PWD=/home/pascal
EDITOR=emacs
LANG=fr_FR@euro
SHLVL=1
HOME=/home/pascal
LOGNAME=pascal
LC_CTYPE=fr_FR.ISO8859-15
SSH_CONNECTION=192.168.200.2 3878 192.168.200.5 22
_=/usr/bin/printenv

</programlisting></para>
      </formalpara>
    </sect2>

    <sect2>
      <title><command>date</command>, <command>cal</command></title>

      <formalpara>
        <title><command>date (1)</command></title>

        <para>Evoquée sans argument cette commande donne la date du jour.
        <programlisting width="80">
<emphasis>EXEMPLE :</emphasis>

$ date
Wed Aug 13 11:31:51 RET 2003                                                    

</programlisting></para>
      </formalpara>

      <formalpara>
        <title><command>cal (1)</command></title>

        <para>Evoquée sans argument cette commande affiche le calendrier du
        mois en cours. <programlisting width="80">
<emphasis>EXEMPLE :</emphasis>

$ cal                                                                           
    August 2003
Su Mo Tu We Th Fr Sa
                1  2
 3  4  5  6  7  8  9
10 11 12 13 14 15 16
17 18 19 20 21 22 23
24 25 26 27 28 29 30
31

</programlisting></para>
      </formalpara>
    </sect2>

    <!-- VERSION ASR DEBUT -->

    <sect2>
      <title>Exercices</title>

      <!-- ELEMENTS A CONSERVER POUR LES TESTS -->

      <!--
      <simplesect>
	<title>Exercice : <quote>Curiosités</quote> autour de la notion de lien symboliques</title>
	<para>
<programlisting width="80">
<emphasis>EXEMPLE GNU/Linux :</emphasis>
<![CDATA[
$ ln -s ~/tmp monrep    # créer d'un lien symb. sur le répertoire ~/tmp         
$ ls -F
bin/  monrep@  test/  tmp/  tootoo  toto  toto.o  toto~
$ mv monrep tmp/        # déplacer le lien symb. dans ~/tmp
$ cd tmp/
$ ls -F
monrep@  titi  toto
$ cd monrep             # se rendre dans monrep
$ pwd
/home/pascal/tmp/monrep
$ ls -F
monrep@  titi  toto
$ cd monrep             # se rendre dans monrep
$ pwd 
/home/pascal/tmp/monrep/monrep
$ ls -F
monrep@  titi  toto
... 
# limite de l'empilement ?
]]>


<emphasis>EXEMPLE FreeBSD :</emphasis>
$ ln -s ~/tmp ldir # créer d'un lien symb. sur le répertoire ~/tmp         
$ ls -F
bin/  ldir@  test/  tmp/  tootoo  toto  toto.o  toto~

$ mv ldir/ tmp/    # déplacer le lien symb. dans ~/tmp, interprété comme un rép.
mv: rename ldir/ to /home/pascal/tmp/ldir : Invalid argument

$ mv monrep tmp/   # déplacer le lien 
$ ls -F tmp/       # ça marche !
ldir@        minicom.log
$ cd tmp/
$ cd ldir; cd ldir; cd ldir
$ pwd              # toujours au même endroit logique
/home/pascal/tmp
$ mv ldir ..
$ rm -rf ldir/     # efface l'objet le rép. cible ~/tmp, mais pas le lien
                   # pour effacer le lien seul, il faut taper rm -f ldir
                   # pas de slash final
</programlisting>
</para>
      </simplesect>

-->

      <simplesect>
        <title>Exercice - 1 - Liens durs (ou physiques)</title>

        <para><orderedlist inheritnum="inherit" numeration="lowerroman"
            spacing="compact">
            <listitem>
              <para>Créer un fichier texte <filename>foo</filename>, contenant
              le seul mot foo, dans le répertoire
              <filename>~/elementBase/part1/synth1/</filename> .</para>
            </listitem>

            <listitem>
              <para>Créer
              <filename>~/elementBase/part1/synth1/dir1/foo2</filename> comme
              lien dur à  <filename>~/foo</filename>. Comment vérifiee que ces
              deux désignations différentes référencent le même objet.</para>
            </listitem>

            <listitem>
              <para>Est-il possible de savoir si un fichier possède plusieurs
              désignations ?</para>
            </listitem>

            <listitem>
              <para>Modifier le contenu de
              <filename>~/elementBase/part1/synth1/dir1/foo2</filename> en lui
              ajoutant du texte (<computeroutput>echo ...
              &gt;&gt;~elementBase/part1/synth1/dir1/foo2</computeroutput>).
              Contenu prévisible de
              <filename>~/elementBase/part1/synth1/foo</filename> ? Le
              vérifier.</para>
            </listitem>

            <listitem>
              <para>Supprimer la désignation
              <filename>~/elementBase/part1/synth1/dir1/foo2</filename>. Que
              devient <filename>~/elementBase/part1/synth1/dir1/foo2</filename>
              ?</para>
            </listitem>

            <listitem>
              <para>Peut-on créer un lien dur
              <filename>~/elementBase/part1/synth1/dir2</filename> à 
              <filename>~/elementBase/part1/synth1/dir1</filename> ? Pourquoi
              ?</para>
            </listitem>

            <listitem>
              <para>Pourquoi les liens durs ne peuvent pas appartenir à  des
              <foreignphrase>filesystem</foreignphrase> différents ?</para>
            </listitem>
          </orderedlist></para>
      </simplesect>

      <simplesect>
        <title>Exercice - 2 - Liens symboliques</title>

        <para><orderedlist inheritnum="inherit" numeration="lowerroman"
            spacing="compact">
            <listitem>
              <para>Créer un fichier texte
              <filename>~/elementBase/part1/synth1/dir2/bar</filename>,
              contenant le seul mot bar, puis un lien symbolique
              <filename>~/elementBase/part1/synth1/barls</filename> vers
              celui-ci. Contrôler avec la commande <command>ls -liR</command>,
              puis avec <command>cat
              ~/elementBase/part1/synth1/barls</command>. Renommer
              <filename>~/elementBase/part1/synth1/dir2/bar</filename> en
              <filename>~/elementBase/part1/synth1/dir3/bar</filename>.
              Contrôler le résultat et conclure.</para>
            </listitem>

            <listitem>
              <para>Tester la transitivité de la notion de lien symbolique
              (<abbrev>i.e.</abbrev> lien vers un lien vers une désignation
              d'un objet du <foreignphrase>filesystem</foreignphrase>).</para>
            </listitem>

            <listitem>
              <para>Tester l'acyclicité du SGF en créant une circularité de
              liens symboliques..</para>
            </listitem>
          </orderedlist></para>
      </simplesect>
    </sect2>

    <!-- VERSION ASR FIN -->
  </sect1>

  <!-- ==================== 2e partie ==================== -->

  <sect1>
    <title>Utilitaires de
    <foreignphrase>textprocessing</foreignphrase></title>

    <para>Nous proposons dans cette partie un bref panoramma des commandes de
    gestion des fichiers au format texte, format retenu par
    <emphasis>Unix</emphasis> car universel<footnote>
        <para><foreignphrase>Write programs that do one thing and do it well.
        Write programs to work together. Write programs to handle text
        streams, because that is a universal interface.
        </foreignphrase></para>
      </footnote> . Un détour par la documentation (<command>man</command>)
    permettra de compléter utiliement ces connaissances.</para>

    <sect2>
      <title>wc, tail, head, cut, nl, pr</title>

      <sect3>
        <title><command>wc (1)</command></title>

        <para>Cette commande [<foreignphrase>word count</foreignphrase>]
        permet de comptabiliser le nombre d'octets, de mots et de lignes du
        fichier qui lui est passé en argument. Dans l'exemple ci-dessous, je
        donne le nombre de lignes du fichier <filename>/etc/group</filename>.
        <programlisting width="80">
<emphasis>EXEMPLE :</emphasis>

$ wc -l /etc/group    # nombre de ligne uniquement, ici                         
     45 /etc/group

</programlisting></para>

        <simplesect>
          <title>Exercice - wc</title>

          <para><orderedlist inheritnum="inherit" numeration="lowerroman"
              spacing="compact">
              <listitem>
                <para>En utilisant la commande <computeroutput>ps -axcw -o
                ppid,pid,user,vsz,time,command</computeroutput>., créez le
                fichier <filename>~/elementBase/part2/process</filename>
                contenant des informations sur les processus en cours.</para>
              </listitem>

              <listitem>
                <para>En utilisant la commande <computeroutput>ps
                -aux</computeroutput>., créez le fichier
                <filename>~/elementBase/part2/ps-aux</filename> contenant des
                informations sur les processus en cours.</para>
              </listitem>

              <listitem>
                <para>Combien de lignes contiennent les fichiers ?</para>
              </listitem>
            </orderedlist></para>
        </simplesect>
      </sect3>

      <sect3>
        <title><command>tail (1)</command></title>

        <para>Cette commande affiche la partie finale (par défaut, les 10
        dernières lignes) du fichier qui lui est passé en argument. Dans
        l'exemple qui suit, on utilise une propriété intéressante, l'option
        <option>-f</option> qui permet d'afficher en permanence la fin d'un
        fichier donné. On peut donc <emphasis>logger</emphasis> en temps réel
        ce qui arrive dans le fichier <filename>/var/log/message</filename>
        (si l'on possède les droits de lecture sur ce fichier). Pour en sortir
        faire un &lt;CTRL&gt;-C.</para>

        <programlisting width="80">
<emphasis>EXEMPLE :</emphasis>

$ tail -f /var/log/messages
Aug  5 16:01:44 Godel /kernel: Connection attempt to UDP 127.0.0.1:512 from 127.
Aug  5 16:17:10 Godel /kernel: Connection attempt to UDP 192.168.200.2:2428 from
Aug  5 16:17:10 Godel su: BAD SU pascal to toor on /dev/ttyp5
Aug  5 16:32:35 Godel su: pascal to toor on /dev/ttyp5
Aug  5 16:48:01 /kernel: pid 33004 (sysinstall), uid 666: exited on signal 11 (c
Aug  5 17:03:28 Godel /kernel: Connection attempt to UDP 192.168.200.2:2438 from
Aug  5 17:18:53 Godel /kernel: Connection attempt to UDP 192.168.200.2:2441 from
Aug  5 17:34:18 Godel /kernel: Connection attempt to UDP 192.168.200.2:2444 from
Aug  5 17:34:18 Godel /kernel: Connection attempt to UDP 192.168.200.2:2445 from
Aug  5 17:49:44 Godel /kernel: Connection attempt to UDP 192.168.200.2:2448 from
^C
$

</programlisting>

        <simplesect>
          <title>Exercice - tail</title>

          <para><orderedlist inheritnum="inherit" numeration="lowerroman"
              spacing="compact">
              <listitem>
                <para>Créez le fichier
                <filename>~/elementBase/part2/procList</filename> en supprimant
                la première ligne du fichier
                <filename>~/elementBase/part2/process</filename>.</para>
              </listitem>
            </orderedlist></para>
        </simplesect>
      </sect3>

      <sect3>
        <title><command>head (1)</command></title>

        <para>Cette commande affiche la partie initiale (par défaut, les 10
        premières lignes) du fichier qui lui est passé en argument.</para>
      </sect3>

      <sect3>
        <title><command>cut (1)</command></title>

        <para>Cette commande permet d'extraire des champs (délimités par des
        caractères), des lignes du fichier ou du flux qui lui est passé en
        argument. Dans l'exemple qui suit, j'extrais les champs 1 (login), 3
        (uid) et 4 (gid) délimités par les caractères <quote>:</quote> du
        fichier <filename>/etc/passwd</filename> : <programlisting width="80">
<emphasis>EXEMPLE :</emphasis>

$ cut -f1,3,4 -d: /etc/passwd
root:0:0
toor:0:11
daemon:1:1
bin:2:2
sys:3:3
sync:4:65534
man:6:12
mail:8:8
news:9:9
uucp:10:10
proxy:13:13
postgres:31:32
backup:34:34
operator:37:37
nobody:65534:65534                                                              
pascal:666:666
corto:667:666
sshd:101:65534

</programlisting></para>
      </sect3>

      <sect3>
        <title><command>nl (1)</command></title>

        <para>Cette commande ajoute un numéro de ligne à  chaque ligne du
        fichier qui lui est passé en argument. <programlisting width="80">
<emphasis>EXEMPLE :</emphasis>

$ nl ~/bin/mylock.sh
     1  #!/bin/sh
       
     2  stty -echo
     3  trap '' 1 2 3 15   # ignorer les signaux
     4  echo -n "Key:"
     5  read key
     6  echo
     7  echo -n "Again:"
     8  read again
     9  echo
    10  if [ "$key" = "$again" ]; then
    11      while [ 1 ]; do
    12          read again
    13          if [ "$key" != "$again" ]; then                                 
    14              echo "What a fair foot !"
    15          else
    16              echo "unlock terminal"          
    17              break
    18          fi
    19      done
    20  else
    21      echo "Mismatch keys"
    22  fi
    23  # restaurer
    24  stty echo
    25  trap 1 2 3 15

</programlisting></para>
      </sect3>

      <sect3>
        <title><command>pr (1)</command></title>

        <para>Cette commande permet de morceler un fichier en plusieurs pages,
        souvent dans le but de l'imprimer. L'exemple montre quelques lignes de
        la deuxième page d'un script Perl : <programlisting width="80">
<emphasis>EXEMPLE :</emphasis>

$  pr ~/bin/logfile-1.2.pl | less
...
Jan  7 14:23 2003 /home/pascal/bin/logfile-1.2.pl Page 2


  open(TEMP, "temp") 
    || die "problème pour ouvrir temp : $!\n";
  @T = split(/\s+/, &lt;TEMP&gt;);
  ($owner, $group) = @T[2,3]; 
  close(TEMP) || warn " problème de fermeture du fichier temp : $!";            
  
  $owner = "$owner" . ":";
  $group = "$group" . ":";
  
  system("cat /etc/passwd | grep $owner &gt; temp");
  open(TEMP, "temp") 
...

</programlisting></para>
      </sect3>
    </sect2>

    <sect2 id="cat">
      <title>Utilitaires cat, tac, more, less, sort, uniq</title>

      <sect3>
        <title><command>cat (1)</command></title>

        <para>Cette commande permet d'imprimer tel quel, sur la sortie
        standard, les contenus des fichiers qui lui sont passés en argument,
        <abbrev>i.e.</abbrev> elle lit le contenu de ces fichiers. Elle permet
        aussi de réaliser la concaténation de plusieurs fichiers dans un seul
        au moyen d'une redirection de la sortie standard. <programlisting
        width="80">
<emphasis>EXEMPLE :</emphasis>

$ cat file1.txt file2.txt file3.txt &gt; file123.txt                               

</programlisting></para>

        <simplesect>
          <title>Exercice - cat</title>

          <para><orderedlist inheritnum="inherit" numeration="lowerroman"
              spacing="compact">
              <listitem>
                <para>Utiliser <command>cat</command> pour écrire deux lignes
                de texte et les mettre dans le fichier
                <filename>~/elementBase/part2/exo1/notes</filename>.</para>
              </listitem>

              <listitem>
                <para>Depuis le fichier
                <filename>~/elementBase/part2/exo1/notes</filename>, écrire la
                commande permettant d'obtenir le fichier
                <filename>~/elementBase/part2/exo1/notesNum</filename>, dont
                les lignes sont numérotées.</para>
              </listitem>
            </orderedlist></para>
        </simplesect>
      </sect3>

      <sect3>
        <title><command>tac</command></title>

        <para>Cette commande <emphasis>GNU/Linux</emphasis> fonctionne comme
        la <command>cat</command>, mais imprime dans l'ordre inverse,
        <abbrev>i.e.</abbrev> commence par la dernière ligne. <programlisting
        width="80">
<emphasis>EXEMPLES :</emphasis>

$ cat file.txt
ligne 1
une autre ligne, la 2 !                                                         
puis la ligne 3

$ tac file.txt
puis la ligne 3
une autre ligne, la 2 !
ligne 1

</programlisting></para>
      </sect3>

      <sect3>
        <title><command>more (1)</command></title>

        <para>Cette commande permet l'affichage du contenu du fichier qui lui
        est passé en argument, en tenant compte des caractéristiques de
        l'écran. L'affichage se fait dont page par page, mais dans un mode
        unidirectionnel (du début vers la fin du fichier). Il est possible de
        faire des recherches sur critères en avant ou en arrière, d'avancer
        dans le fichier ligne par ligne ou page par page,
        <abbrev>c.f.</abbrev> commande help de <command>more</command>.</para>

        <para>En pratique, on préfère utiliser la commande
        <command>less</command> (<abbrev>c.f.</abbrev> section suivante), qui
        propose d'avantages de fonctionnalités.</para>
      </sect3>

      <sect3>
        <title><command>less (1)</command></title>

        <para>Cette commande généralise la commande précédente en reprenant
        ses caractéristiques d'affichage et y ajoutant la possibilité d'aller
        en arrière <abbrev>i.e.</abbrev> de remonter dans le fichier.</para>

        <simplesect>
          <title>Exercice - Less</title>

          <para><orderedlist inheritnum="inherit" numeration="lowerroman"
              spacing="compact">
              <listitem>
                <para>Comment dire à  <command>less</command> d'ouvrir le
                fichier <filename>~/elementBase/part2/procList</filename> en
                plaçant en haut de l'écran la ligne 15 ?</para>
              </listitem>

              <listitem>
                <para>Comment dire à  <command>less</command> d'ouvrir le
                fichier <filename>~/elementBase/part2/procList</filename> en
                plaçant en haut de l'écran la première ligne oà¹ apparaît le
                motif "tty" ?</para>
              </listitem>

              <listitem>
                <para>Quelles sont les deux commandes de
                <command>less</command> qui permettent de chercher un motif
                dans un fichier, respectivement après et avant la position
                courante ?</para>
              </listitem>

              <listitem>
                <para>Quelles sont les commandes qui permettent d'aller à  la
                prochaine (resp. précédente) occurence du motif recherché à 
                travers tous les fichiers édités ?</para>
              </listitem>

              <listitem>
                <para>Comment chercher dans un fichier le caractère / ?</para>
              </listitem>
            </orderedlist></para>
        </simplesect>
      </sect3>

      <sect3>
        <title><command>sort (1)</command></title>

        <para>Cette commande permet de trier le contenu du fichier qui lui est
        passé en argument dans l'ordre lexicographique. Consulter le
        <command>man sort</command> pour avoir tous les détails. Dans
        l'exemple qui suit, je trie le fichier
        <filename>/etc/passwd</filename> selon l'ordre numérique sur le champ
        3 (uid) puis sur le champ 4 (gid). Afin de limiter l'affichage,
        certaines lignes ont été volontairement enlevées du résultat.
        <programlisting width="80">
<emphasis>EXEMPLE :</emphasis>

$  sort -n -k 3,4 -t ":" /etc/passwd
root:x:0:0:root:/root:/bin/bash
toor:x:0:11:toor's account:/root:/bin/bash
daemon:x:1:1:daemon:/usr/sbin:/bin/false
bin:x:2:2:bin:/bin:/bin/false
sys:x:3:3:sys:/dev:/bin/false
sync:x:4:65534:sync:/bin:/bin/sync
man:x:6:12:man:/var/cache/man:/bin/false
mail:x:8:8:mail:/var/mail:/bin/sh
news:x:9:9:news:/var/spool/news:/bin/false
uucp:x:10:10:uucp:/var/spool/uucp:/bin/false
proxy:x:13:13:proxy:/bin:/bin/false
postgres:x:31:32:postgres:/var/lib/postgres:/bin/nologin                        
backup:x:34:34:backup:/var/backups:/bin/false
operator:x:37:37:Operator:/var:/bin/false
sshd:x:101:65534::/var/run/sshd:/bin/false
postfix:x:102:101::/var/spool/postfix:/bin/false
pascal:x:666:666:Pascal P.,,,:/home/pascal:/bin/bash
corto:x:667:666:testing account:/:/bin/false
nobody:x:65534:65534:nobody:/nonexistent:/bin/false

</programlisting></para>

        <simplesect>
          <title>Exercice - Sort</title>

          <para><orderedlist inheritnum="inherit" numeration="lowerroman"
              spacing="compact">
              <listitem>
                <para>Triez le fichier
                <filename>~/elementBase/part2/procList</filename> sur le champ
                PPID puis sur le champ PID.</para>
              </listitem>

              <listitem>
                <para>Triez les processus le fichier
                <filename>~/elementBase/part2/procList</filename> sur la taille
                de leur mémoire virtuelle.</para>
              </listitem>
            </orderedlist></para>
        </simplesect>
      </sect3>

      <sect3>
        <title><command>uniq (1)</command></title>

        <para>Cette commande permet de supprimer les doublons dans un fichier
        préalablement trié. On s'inspire de l'exemple précédent, avec cette
        fois ci un tri uniquement effecttué sur le champ gid (dans l'ordre
        numérique croissant), puis nous récuperons ces gids (uniquement, avec
        <command>awk</command>, que nous verrons dans <xref
        linkend="id_awk" /> ) et supprimons les doublons : <programlisting
        width="80">
<emphasis>EXEMPLE :</emphasis>

$ sort -n -k 4 -t ":" /etc/passwd | awk -F ":" '{print $4}' | uniq              
0
1
2
3
8
9
10
11
12
13
32
34
37
101
666
65534

</programlisting></para>

        <simplesect>
          <title>Exercice</title>

          <para><orderedlist inheritnum="inherit" numeration="lowerroman"
              spacing="compact">
              <listitem>
                <para>En utilisant
                <filename>~/elementBase/part2/procList</filename>, donnez la
                liste ordonnée des processus qui ont au moins un fils.</para>
              </listitem>
            </orderedlist></para>
        </simplesect>
      </sect3>
    </sect2>

    <sect2>
      <title>expand, unexpand, tr</title>

      <sect3>
        <title><command>expand (1)</command></title>

        <para>Cette commande permet de convertir les caractères de
        tabulations, d'un fichier passé en argument, en caractères
        d'espacement. <programlisting width="80">
<emphasis>EXEMPLE :</emphasis>

$ cat in                                                                        
#Societe        Contact         Telephone
TOTOR   Rivière 0262 994545
HADJEE  Ingar   0262 983399
HOULAN  Sautron 0262 999978

$ cat in | grep -v ^# | expand -20
TOTOR               Rivière             0262 994545
HADJEE              Ingar               0262 983399
HOULAN              Sautron             0262 999978 

</programlisting></para>
      </sect3>

      <sect3>
        <title><command>unexpand (1)</command></title>

        <para>Cette commande (symétrique de la précédente) permet de convertir
        les caractères d'espacement, d'un fichier passé en argument en
        caractères de tabulations.</para>
      </sect3>

      <sect3>
        <title><command>tr (1)</command></title>

        <para>Cette commande permet de transcoder les caractères d'un flux
        d'entrée selon un modèle. Dans l'exemple, je montre comment
        transformer un flux en majuscules, puis un décalage (a remplacé par e,
        b par f, modulo les 26 lettres de l'alphabet). <programlisting
        width="80">
<emphasis>EXEMPLE :</emphasis>

$ cat file.txt                                                                  
Voici la 1ere ligne...
Une autre ligne, la      2 !
Puis la ligne    3

$ tr a-z A-Z &lt; file.txt
VOICI LA 1ERE LIGNE...
UNE AUTRE LIGNE, LA      2 !
PUIS LA LIGNE    3

$ tr a-z efghijklmnopqrstuvwxyzabcd  &lt; file.txt 
Vsmgm pe 1ivi pmkri...
Uri eyxvi pmkri, pe      2 !
Pymw pe pmkri    3

</programlisting></para>
      </sect3>
    </sect2>

    <sect2>
      <title>od, split, fmt, fold</title>

      <sect3>
        <title><command>od (1)</command></title>

        <para>Cette commande transforme le flux d'entrée (fichier ou
        redirection) au format octal ou héxadécimal. Dans l'exemple suivant,
        j'affiche le contenu du fichier <filename>file.txt</filename> sous
        forme de caractères et pour chacun d'eux son code héxadécimal associé
        : <programlisting width="80">
<emphasis>EXEMPLE :</emphasis>

$ cat file.txt
ligne 1
une autre ligne, la      2 !
puis la ligne    3

$ od -ax file.txt  # sortie ascii et héxadécimale
0000000   l   i   g   n   e  sp   1  nl   u   n   e  sp   a   u   t   r         
        696c 6e67 2065 0a31 6e75 2065 7561 7274
0000020   e  sp   l   i   g   n   e   ,  sp   l   a  ht  sp   2  sp   !
        2065 696c 6e67 2c65 6c20 0961 3220 2120
0000040  nl   p   u   i   s  sp   l   a  sp   l   i   g   n   e  ht  sp
        700a 6975 2073 616c 6c20 6769 656e 2009
0000060   3  nl
        0a33
0000062

</programlisting> Remarque : le fichier fait 50 (= 62 en octal) octets. Le
        code 69<subscript>h</subscript> désigne la lettre i, tandis que
        6c<subscript>h</subscript> désigne le l.</para>
      </sect3>

      <sect3>
        <title><command>split (1)</command></title>

        <para>Cette commande permet de découper un gros fichier en plusieurs
        morceaux plus petit. Dans l'exemple, je dispose d'un fichier de
        3436583 octets, que je voudrais transférer sur disquettes, chacune
        disposant d'un mégaoctet (= 1048576 octets) de libre au plus, il
        faudra donc 4 disquettes. Noter, l'utilisation du prefixe pour
        simplifier le travail, le reste du nom est généré automatiquement :
        <programlisting width="80">
<emphasis>EXEMPLE :</emphasis>

$ ls -l foo.pdf 
-rw-------    1 pascal   gnu       3436583 Aug  6 09:03 foo.pdf                 

$ split -b 1048576 foo.pdf foo-
$ ls -l foo*
-rw-------    1 pascal   gnu       1048576 Aug  6 09:10 foo-aa
-rw-------    1 pascal   gnu       1048576 Aug  6 09:10 foo-ab
-rw-------    1 pascal   gnu       1048576 Aug  6 09:10 foo-ac
-rw-------    1 pascal   gnu        290855 Aug  6 09:10 foo-ad
-rw-------    1 pascal   gnu       3436583 Aug  6 09:03 foo.pdf

</programlisting> Pour reconstituer le tout il suffit de concaténer les
        morceaux ensemble, comme suit : <programlisting width="80">
<emphasis>EXEMPLE :</emphasis>

$ cat foo-aa foo-ab foo-ac foo-ad &gt; nfoo.pdf                                    
$ ls -l nfoo.pdf
-rw-------    1 pascal   gnu       3436583 Aug  6 09:14 nfoo.pdf

</programlisting></para>
      </sect3>

      <sect3>
        <title><command>fmt (1)</command></title>

        <para>Cette commande reformate les paragraphes du fichier qui lui est
        passé en argument. Dans l'exemple qui suit, je limite la longueur de
        la ligne à  60 caractères. <programlisting width="80">
<emphasis>EXEMPLE :</emphasis>

$ cat file.txt 
Paragraphe numéro un : ceci est un exemple de paragraphe tapé au kilomètre sans 
souci de mise en page histoire de voir un peu ce qu'il se passe. Deuxième phrase
 du premier paragraphe. 
Une autre ligne, la      2 !
Puis la ligne    3


$ fmt -uw 60 file.txt 
Paragraphe numéro un : ceci est un exemple de paragraphe
tapé au kilomètre sans souci de mise en page histoire de
voir un peu ce qu'il se passe. Deuxième phrase du premier
paragraphe.  Une autre ligne, la 2 !  Puis la ligne 3

</programlisting></para>
      </sect3>

      <sect3>
        <title><command>fold (1)</command></title>

        <para>Cette commande contraint à  une longueur donnée, chaque ligne du
        fichier qui lui est passé en argument. Il n'y a pas de reformatage.
        <programlisting width="80">
<emphasis>EXEMPLE :</emphasis>

$ cat file.txt 
Paragraphe numéro un : ceci est un exemple de paragraphe tapé au kilomètre sans 
souci de mise en page histoire de voir un peu ce qu'il se passe. Deuxième phrase
 du premier paragraphe. 
Une autre ligne, la      2 !
Puis la ligne    3

$ fold -w 60 file.txt 
Paragraphe numéro un : ceci est un exemple de paragraphe tap
é au kilomètre sans souci de mise en page histoire de voir u
n peu ce qu'il se passe. Deuxième phrase du premier paragrap
he. 
Une autre ligne, la      2 !
Puis la ligne    3

</programlisting></para>
      </sect3>
    </sect2>

    <sect2>
      <title>paste, join, tee</title>

      <sect3>
        <title><command>paste (1)</command></title>

        <para>Cette commande fusionne les lignes des différents fichiers (un
        ou plus) qui lui sont passés en argument. <programlisting width="80">
<emphasis>EXEMPLE :</emphasis>

$ cat in1                                                                       
ligne 1
line 2
ligne 3 ...
line 444
 
$ cat in2
line aaaaaaaaaaaaaaaaaaaaaaaaaaa bbbbbaaaaa
ligne bbbbbbbbbbbbbbbbbbbbbbbbbbb

$ paste in1 in2
ligne 1 line aaaaaaaaaaaaaaaaaaaaaaaaaaa bbbbbaaaaa
line 2  ligne bbbbbbbbbbbbbbbbbbbbbbbbbbb
ligne 3 ...
line 444

$ paste in2 in1
line aaaaaaaaaaaaaaaaaaaaaaaaaaa bbbbbaaaaa     ligne 1
ligne bbbbbbbbbbbbbbbbbbbbbbbbbbb       line 2
        ligne 3 ...
        line 444


</programlisting></para>
      </sect3>

      <sect3>
        <title><command>join (1)</command></title>

        <para>Cette commande similaire à  <command>paste</command>, utilise un
        champ (par défaut le premier) commun à  chaque ligne des deux fichiers
        donnés en entrée, pour les fusionner en une ligne. Le champ commun
        n'est pas répété. <programlisting width="80">
<emphasis>EXEMPLE :</emphasis>

$ cat in1                                                                       
ligne 1
line 2
ligne 3 ...
line 444
 
$ cat in2
ooo line aaaaaaaaaaaaaaaaaaaaaaaaaaa bbbbbaaaaa
aaa ligne bbbbbbbbbbbbbbbbbbbbbbbbbbb

$ join  -1 1 -2 2 in1 in2
line 2 aaaaaaaaaaaaaaaaaaaaaaaaaaa bbbbbaaaaa
ligne 3 ... bbbbbbbbbbbbbbbbbbbbbbbbbbb

$ join -1 2 -2 1 in2 in1
line ooo aaaaaaaaaaaaaaaaaaaaaaaaaaa bbbbbaaaaa 2
ligne aaa bbbbbbbbbbbbbbbbbbbbbbbbbbb 3 ...

</programlisting> <emphasis role="bold">Précision :</emphasis> tout ce passe
        comme suit, il y a <quote>alignement</quote> sur : <programlisting
        width="80">
<emphasis>EXEMPLE :</emphasis>

# in1                         in2                                               
ligne 1<emphasis role="bold">
line 2                        ooo line aaaaaaaaaaaaaaaaaaaaaaaaaaa bbbbbaaaaa   
ligne 3 ...                   aaa ligne bbbbbbbbbbbbbbbbbbbbbbbbbbb
</emphasis>line 444

</programlisting></para>

        <simplesect>
          <title>Exercice</title>

          <para><orderedlist inheritnum="inherit" numeration="lowerroman"
              spacing="compact">
              <listitem>
                <para>En utilisant les fichiers
                <filename>~/elementBase/part2/procList</filename>, et
                <filename>~/elementBase/part2/p</filename>s-aux, créez le
                fichier <filename>~/elementBase/part2/procList2</filename>
                contenant les champs PID, PPID, USER, %CPU et COMMAND, en
                séparant les champs par des tabulations.</para>
              </listitem>
            </orderedlist></para>
        </simplesect>
      </sect3>

      <sect3>
        <title><command>tee (1)</command></title>

        <para>Cette commande copie sur la sortie standard et dans les fichiers
        qui lui sont passés en argument le flux en provenance de l'entrée
        standard. Particulièrement utile quand on veut
        <foreignphrase>logger</foreignphrase> des évènements dans un fichier
        et en même temps les voir sur un écran. <programlisting width="80">
<emphasis>EXEMPLE :</emphasis>

$ tee out1 out2 &lt; file.txt                                                      
Voici la 1ere ligne...
Une autre ligne, la      2 !
Puis la ligne    3

$ cat out1
Voici la 1ere ligne...
Une autre ligne, la      2 !
Puis la ligne    3

$ cat out2
Voici la 1ere ligne...
Une autre ligne, la      2 !
Puis la ligne    3

</programlisting></para>
      </sect3>
    </sect2>

    <!-- VERSION ASR DEBUT -->

    <sect2>
      <title>Exercices</title>

      <simplesect>
        <title>Exercice - <emphasis>Textprocessing</emphasis> (1)</title>

        <para><orderedlist numeration="lowerroman" spacing="compact">
            <listitem>
              <para>Trier le fichier des mots de passe en majeur sur le champ
              <emphasis>gid</emphasis> (4<superscript>e</superscript>) et en
              mineur sur le champ <emphasis>uid</emphasis>
              (3<superscript>e</superscript>).</para>
<!--
              <formalpara>
                <title>Proposition de correction</title>

                <para><programlisting width="80">
<emphasis>CODE :</emphasis>

$ sort -t":" -n -k 4 -k 3/etc/passwd                                            
#
root:*:0:0:Charlie &amp;:/root:/bin/csh
toor:*:0:0:Bourne-again Superuser:/root:/bin/tcsh
daemon:*:1:1:Owner of many system processes:/root:/sbin/nologin
operator:*:2:5:System &amp;:/:/sbin/nologin
pop:*:68:6:Post Office Owner:/nonexistent:/sbin/nologin
bin:*:3:7:Binaries Commands and Source:/:/sbin/nologin
news:*:8:8:News Subsystem:/:/sbin/nologin
man:*:9:9:Mister Man Pages:/usr/share/man:/sbin/nologin
games:*:7:13:Games pseudo-user:/usr/games:/sbin/nologin
# $FreeBSD: src/etc/master.passwd,v 1.25.2.6 2002/06/30 17:57:17 des Exp $
sshd:*:22:22:Secure Shell Daemon:/var/empty:/sbin/nologin
smmsp:*:25:25:Sendmail Submission User:/var/spool/clientmqueue:/sbin/nologin
mailnull:*:26:26:Sendmail Default User:/var/spool/mqueue:/sbin/nologin
bind:*:53:53:Bind Sandbox:/:/sbin/nologin
cyrus:*:60:60:the cyrus mail server:/nonexistent:/sbin/nologin
uucp:*:66:66:UUCP pseudo-user:/var/spool/uucppublic:/usr/libexec/uucp/uucico
xten:*:67:67:X-10 daemon:/usr/local/xten:/sbin/nologin
pgsql:*:70:70:PostgreSQL Daemon:/usr/local/pgsql:/bin/sh
www:*:80:80:World Wide Web Owner:/nonexistent:/sbin/nologin
mysql:*:88:88:MySQL Daemon:/var/db/mysql:/sbin/nologin
pascal:*:666:666:Pascal P;:/home/pascal:/bin/tcsh
miji:*:667:666:Miji M.P.:/home/miji:/bin/tcsh
postfix:*:1001:1001:Postfix Mail System:/var/spool/postfix:/sbin/nologin
jabber:*:1002:1003:Jabber Daemon:/nonexistent:/nonexistent
stunnel:*:1003:1004:stunnel Daemon:/nonexistent:/sbin/nologin
tty:*:4:65533:Tty Sandbox:/:/sbin/nologin
kmem:*:5:65533:KMem Sandbox:/:/sbin/nologin
nobody:*:65534:65534:Unprivileged user:/nonexistent:/sbin/nologin

</programlisting></para>
              </formalpara> -->
            </listitem>

            <listitem>
              <para>Sous <emphasis>FreeBSD</emphasis> le fichier
              <filename>/etc/passwd</filename> contient des commentaires,
              lignes commençant par le symbole #. Reprendre le travail
              précédent en éliminant les lignes de commentaires.</para>
<!--
              <formalpara>
                <title>Proposition de correction</title>

                <para><programlisting width="80">

$ clear &amp;&amp; grep -v '^#' /etc/passwd | sort -t ":" -n -k 4 -k 3                  
root:*:0:0:Charlie &amp;:/root:/bin/csh
toor:*:0:0:Bourne-again Superuser:/root:/bin/tcsh
daemon:*:1:1:Owner of many system processes:/root:/sbin/nologin
operator:*:2:5:System &amp;:/:/sbin/nologin
pop:*:68:6:Post Office Owner:/nonexistent:/sbin/nologin
bin:*:3:7:Binaries Commands and Source:/:/sbin/nologin
news:*:8:8:News Subsystem:/:/sbin/nologin
man:*:9:9:Mister Man Pages:/usr/share/man:/sbin/nologin
games:*:7:13:Games pseudo-user:/usr/games:/sbin/nologin
sshd:*:22:22:Secure Shell Daemon:/var/empty:/sbin/nologin
smmsp:*:25:25:Sendmail Submission User:/var/spool/clientmqueue:/sbin/nologin
mailnull:*:26:26:Sendmail Default User:/var/spool/mqueue:/sbin/nologin
bind:*:53:53:Bind Sandbox:/:/sbin/nologin
cyrus:*:60:60:the cyrus mail server:/nonexistent:/sbin/nologin
uucp:*:66:66:UUCP pseudo-user:/var/spool/uucppublic:/usr/libexec/uucp/uucico
xten:*:67:67:X-10 daemon:/usr/local/xten:/sbin/nologin
pgsql:*:70:70:PostgreSQL Daemon:/usr/local/pgsql:/bin/sh
www:*:80:80:World Wide Web Owner:/nonexistent:/sbin/nologin
mysql:*:88:88:MySQL Daemon:/var/db/mysql:/sbin/nologin
pascal:*:666:666:Pascal P;:/home/pascal:/bin/tcsh
miji:*:667:666:Miji M.P.:/home/miji:/bin/tcsh
postfix:*:1001:1001:Postfix Mail System:/var/spool/postfix:/sbin/nologin
jabber:*:1002:1003:Jabber Daemon:/nonexistent:/nonexistent
stunnel:*:1003:1004:stunnel Daemon:/nonexistent:/sbin/nologin
tty:*:4:65533:Tty Sandbox:/:/sbin/nologin
kmem:*:5:65533:KMem Sandbox:/:/sbin/nologin
nobody:*:65534:65534:Unprivileged user:/nonexistent:/sbin/nologin

</programlisting></para>
              </formalpara> -->
            </listitem>
          </orderedlist></para>
      </simplesect>

      <simplesect>
        <title>Exercice - <emphasis>Textprocessing</emphasis> (2)</title>

        <para><orderedlist numeration="lowerroman" spacing="compact">
            <listitem>
              <para>Remplacer le séparateur de champ (:) du fichier
              <filename>/etc/passwd</filename> par le séparateur de tabulation
              horizontal '\t'. Mettre le tout dans un fichier intitulé
              <filename>~/mypasswd</filename>. Vérifier le résultat.</para>

              <formalpara>
                <title>Proposition de correction</title>

                <para><programlisting width="80">

$ cat /etc/passwd | tr ":" "\t" &gt; ~/mypasswd                                    

</programlisting></para>
              </formalpara>
            </listitem>

            <listitem>
              <para>Vous avez sans doute remarqué un défaut d'alignement des
              colonnes. Proposer une solution permettant un alignement de
              chaque colonne, sans décalage à  l'affichage. Même fichier de
              départ, même fichier d'arrivée</para>

              <formalpara>
                <title>Proposition de correction</title>

                <para><programlisting width="80">

$ cat /etc/passwd | tr ":" "\t" | expand -32 &gt; ~/mypasswd                       

</programlisting></para>
              </formalpara>
            </listitem>
          </orderedlist></para>
      </simplesect>

      <simplesect>
        <title>Exercice - <emphasis>Textprocessing</emphasis> (3)</title>

        <para><itemizedlist mark="" spacing="compact">
            <listitem>
              <para><quote>Projeter</quote> le fichier
              <filename>/etc/passwd</filename> sur les champs
              &lt;<emphasis>nom</emphasis>, <emphasis>uid</emphasis>,
              <emphasis>gid</emphasis>, <emphasis>shell</emphasis>&gt;, le
              séparateur final sera le '\t'.</para>

              <formalpara>
                <title>Proposition de correction</title>

                <para><programlisting width="80">

$ cat /etc/passwd | cut -d: -f 1,3,4,7 | tr ":" "\t" &gt; ~/mypasswd               

</programlisting></para>
              </formalpara>
            </listitem>
          </itemizedlist></para>
      </simplesect>
    </sect2>

    <!-- VERSION ASR FIN -->
  </sect1>

  <!-- ==================== 3e partie ==================== -->

  <!-- VERSION ASR DEBUT -->

  <sect1>
    <title>Eléments d'initiation à  <command>sed</command></title>

    <sect2>
      <title>Principes généraux</title>

      <para>Sed et Awk sont deux outils de
      <foreignphrase>textprocessing</foreignphrase>, invoqués de la même
      manière :</para>

      <para><command>command [options] script filename</command></para>

      <para>Comme la plupart des programmes UNIX, sed et awk peuvent lire sur
      l'entrée standard et écrire sur la sortie standard, mais aussi recevoir
      un flux de données depuis un fichier, et bien sûr rediriger les sorties
      vers un fichier.</para>

      <para>Le script spécifie les intructions à  exécuter, et doit être quoté
      (encadré d'apostrophes) si il est directement codé sur la ligne de
      commande. Une option est commune à  <command>awk</command> et
      <command>sed</command>, <option>-f</option> , qui permet de spécifier un
      script externe.</para>

      <para><command>sed -f scriptfile inputfile</command></para>

      <para>La figure ci-dessous montre le fonctionnement de base de sed et
      awk. Chaque programme lit ligne par ligne le fichier d'entrée, en fait
      une copie, et exécute les instructions prévues dans le script sur cette
      copie. Les changement n'affectent pas le fichier source.</para>

      <figure>
        <title>Fonctionnement de Sed et Awk</title>

        <mediaobject>
          <imageobject>
            <imagedata fileref="sed_awk.jpg" />
          </imageobject>
        </mediaobject>
      </figure>
    </sect2>

    <sect2>
      <title>Commandes Sed</title>

      <orderedlist>
        <listitem>
          <para><emphasis>Commande de substitution</emphasis></para>

          <itemizedlist>
            <listitem>
              <para>La commande s permet d'effectuer des substitutions suivant
              la syntaxe : <command>sed -e
              's/expr-régulière/remplacement/options'</command></para>
            </listitem>

            <listitem>
              <para>Options</para>

              <itemizedlist>
                <listitem>
                  <para>Sans précision, la commande ne s'applique qu'à  la 1ère
                  occurence de chaque ligne</para>
                </listitem>

                <listitem>
                  <para><option>0...9</option> : indique que la substitution
                  ne s'applique qu'à  la nième occurence</para>
                </listitem>

                <listitem>
                  <para><option>g </option>: effectue les modifications sur
                  toutes les occurences trouvées</para>
                </listitem>
              </itemizedlist>
            </listitem>

            <listitem>
              <para>Exemple : <command>sed -e 's/moi/toi/g' fich.moi &gt;
              fich.toi</command> le fichier fich.moi est parcouru, à  chaque
              occurrence de "moi", ce mot est remplcé par "toi" et le nouveau
              fichier est sauvegardé sous le nom fich.toi</para>
            </listitem>
          </itemizedlist>
        </listitem>

        <listitem>
          <para><emphasis>Destruction ou sélection</emphasis></para>

          <itemizedlist>
            <listitem>
              <para>Cette option permet de filtrer les lignes qui satisfont
              une expression régulière. Ces lignes ne sont pas détruites dans
              le fichier d'origine, mais ne sont pas transmise en
              sortie.</para>
            </listitem>

            <listitem>
              <para>Par exemple, pour détruire toutes les lignes vide d'un
              fichier : <command>sed -e '/^$/d'</command> </para>
            </listitem>
          </itemizedlist>
        </listitem>

        <listitem>
          <para><emphasis>Ajout, insertion et modification</emphasis></para>

          <itemizedlist>
            <listitem>
              <para>Pour utiliser ces commandes, il est nécessaire de les
              saisir sur plusieurs lignes</para>

              <para><command>sed [adresse] commande\
              expression</command></para>
            </listitem>

            <listitem>
              <para>La commande peut être :</para>

              <itemizedlist>
                <listitem>
                  <para><command>a</command> pour ajout ; </para>
                </listitem>

                <listitem>
                  <para><command>i</command> pour insertion ; </para>
                </listitem>

                <listitem>
                  <para><command>c</command> pour modification</para>
                </listitem>
              </itemizedlist>
            </listitem>

            <listitem>
              <para>Exemple : </para>

              <para><command>/&lt;Neotech 3&gt;/i\ CPEN GREATTA - NEOTECH 3\
              Cité scolaire du butor</command></para>
            </listitem>
          </itemizedlist>
        </listitem>
      </orderedlist>
    </sect2>

    <sect2>
      <title>Quelques exemples</title>

      <para>Exemple : supprimer les lignes commençant par un commentaire dans
      le fichier suivant : <filename>/etc/hosts</filename> <programlisting
      width="80">
<emphasis>EXEMPLE :</emphasis>

$ sed -e '/^#/d' /etc/hosts &gt; ~/myhosts                                         

</programlisting> Le fichier résultant est nommé
      <filename>~/myhosts</filename>. L'expression utilisée est vraie pour
      toute chaîne commençant par le caractère # (marque de commentaire dans
      un fichier).</para>

      <para>Remplacer toutes les occurences de l'interface rl0 du fichier
      (<emphasis>FreeBSD</emphasis>) <filename>/etc/ipf.conf</filename>, par
      l'interface xl1 : <programlisting width="80">
<emphasis>EXEMPLE :</emphasis>

# sed -e 's/rl0/xl1/g' /etc/ipf.conf &gt; /etc/ipf.conf.new                        

</programlisting> Le # dénote ici une opération effectuée en tant que
      <emphasis>super</emphasis>-utilisateur root. L'expression commence par
      un <emphasis>s</emphasis>, lequel indique une opération de substitution.
      Le <emphasis>g</emphasis>, quant à  lui indique que tous les
      remplacements sur une ligne doivent être fait, en son abscence seule la
      première occurence trouvée sur la ligne serait remplacée.</para>

      <formalpara>
        <title>Quelques expressions régulières</title>

        <para>Ces exemples montrent l'utilisation d'expressions régulières,
        nous rappelons dans ce qui suit quelques méta-caractères importants :
        <table>
            <title>Expressions régulières</title>

            <tgroup align="left" cols="3">
              <colspec colname="c1" colnum="1" colwidth="1*+1" />

              <colspec colname="c2" colnum="2" colwidth="4*+1" />

              <colspec colname="c3" colnum="3" colwidth="4*+1" />

              <thead>
                <row>
                  <entry>Caractère</entry>

                  <entry>Description</entry>

                  <entry>Exemple</entry>
                </row>
              </thead>

              <tbody>
                <row>
                  <entry>^</entry>

                  <entry>Correspondance avec le début de ligne</entry>

                  <entry><computeroutput>/^#/</computeroutput> ligne
                  commençant par un un #.</entry>
                </row>

                <row>
                  <entry>$</entry>

                  <entry>Correspondance avec la fin de ligne</entry>

                  <entry><computeroutput>/^$/</computeroutput> ligne
                  blanche.</entry>
                </row>

                <row>
                  <entry>.</entry>

                  <entry>Correspondance avec un caractère quelconque</entry>

                  <entry><computeroutput>/../</computeroutput> ligne contenant
                  au moins deux caractères quelconques.</entry>
                </row>

                <row>
                  <entry>*</entry>

                  <entry>Correspondance avec 0 ou plusieurs caractères
                  quelconques.</entry>

                  <entry><computeroutput>/^a*/</computeroutput> ligne
                  commençant par a suivit par n'importe quoi.</entry>
                </row>

                <row>
                  <entry>[]</entry>

                  <entry>Correspondance avec tout caractères de
                  l'intervalle</entry>

                  <entry><computeroutput>/[abc]$/</computeroutput> ligne se
                  terminant par le motif abc.</entry>
                </row>
              </tbody>
            </tgroup>
          </table></para>
      </formalpara>

      <para>Donnons un autre exemple de combinaison d'expressions régulières.
      On cherche à  imprimer (si elle existe) la fonction main d'un script Perl
      : <programlisting width="80">
<emphasis>EXEMPLE :</emphasis>

$ cd bin ; sed -n -e '/sub[[:space:]]*main[[:space:]]*{/, /^}/p' *.pl | less    

</programlisting> La première partie de cette expression régulière
      <computeroutput>sub[[:space:]]*main[[:space:]]*{</computeroutput> permet
      de trouver le début de la définition de la fonction
      <emphasis>main</emphasis>, tandis que la seconde
      <computeroutput>/^}/</computeroutput> trouve la fin du bloc de cette
      fonction. La classe spéciale
      <computeroutput>[[:space:]]</computeroutput> permet de dénoter un
      caractère espace ou un caractère TAB. Enfin, la commande
      <emphasis>p</emphasis> imprime les lignes qui vérifient la
      condition.</para>

      <formalpara>
        <title>Quelques classes</title>

        <para><table>
            <title>Expressions régulières</title>

            <tgroup align="left" cols="2">
              <colspec colname="c1" colnum="1" colwidth="1*+1" />

              <colspec colname="c2" colnum="2" colwidth="4*+1" />

              <thead>
                <row>
                  <entry>Classe</entry>

                  <entry>Sémantique</entry>
                </row>
              </thead>

              <tbody>
                <row>
                  <entry>[:alnum:]</entry>

                  <entry>Caractères alphanumérique : [a-zA-Z0-9].</entry>
                </row>

                <row>
                  <entry>[:alpha:]</entry>

                  <entry>Caractères alphabétiques : [a-zA-Z].</entry>
                </row>

                <row>
                  <entry>[:blank:]</entry>

                  <entry>Caractère espace ou tabulation.</entry>
                </row>

                <row>
                  <entry>[:digit:]</entry>

                  <entry>Chiffre [0-9].</entry>
                </row>

                <row>
                  <entry>[:lower:]</entry>

                  <entry>Caractères minuscules [a-z].</entry>
                </row>

                <row>
                  <entry>[:space:]</entry>

                  <entry>Espace.</entry>
                </row>

                <row>
                  <entry>[:upper:]</entry>

                  <entry>Caractères majuscules [A-Z].</entry>
                </row>

                <row>
                  <entry>[:cntl:]</entry>

                  <entry>Caractère de contrôle.</entry>
                </row>

                <row>
                  <entry>[:graph:]</entry>

                  <entry>Caractère visibles (donc sans l'espace).</entry>
                </row>

                <row>
                  <entry>[:print:]</entry>

                  <entry>Caractère autres que les caractères de
                  contrôle.</entry>
                </row>

                <row>
                  <entry>[:punct:]</entry>

                  <entry>caractères de ponctuation.</entry>
                </row>

                <row>
                  <entry>[:xdigit:]</entry>

                  <entry>Chiffres héxadécimaux [0-9a-fA-F].</entry>
                </row>
              </tbody>
            </tgroup>
          </table></para>
      </formalpara>

      <para>Donnons maintenant un autre exemple faisant intervenir la
      mémorisation d'expression. On veut cette fois ci remplacer les
      occurences d'adresses IP du fichier <filename>/etc/hosts</filename>, par
      leur adresse dans le domaine in-addr.arpa : <programlisting width="80">
<emphasis>EXEMPLE :</emphasis>

$ awk -F" " '{print $1}' /etc/hosts | sed -e 's/\([[:digit:]]*\)\.\([[:digit:]]*
\)\.\([[:digit:]]*\)\.\([[:digit:]]*\)/arpa.in-addr.\3.\2.\1/' -e '/^#/d'

arpa.in-addr.200.168.192
arpa.in-addr.200.168.192

arpa.in-addr.1.168.192
arpa.in-addr.1.168.192

</programlisting> On utilise maintenant les parenthèses de mémorisation,
      autour de classes. L'opérateur * permet d'attendre plusieurs chiffres.
      On reconnaît l'expression qui permet de filtrer les adresses IPv4.
      L'expression \3 dénote la troisième expression mémorisée
      <abbrev>i.e.</abbrev> le troisième octet, tandis que \2 désigne la
      deuxième expression...</para>

      <para>On peut combiner les instructions, il suffit pour cela de rajouter
      autant d'option <option>-e</option> que nécessaire. Si cela devient trop
      complexe, on peut tout placer dans un fichier et l'appeler au besoin
      avec l'option <option>-f</option>.</para>

      <para>Il est possible d'effectuer plusieurs transformations sur la même
      région (zone dénotée par un début et une fin : étiquettes ou numéro de
      lignes). Dans l'exemple qui suit nous proposons de transformer certains
      termes dans une région dont le début est marquée par une ligne
      commençant par le mot BEGIN et se terminant par le mot END (ou la fin de
      fichier si ce mot n'est pas trouvé). <programlisting width="80">
<emphasis>EXEMPLE :</emphasis>

#
# ~/mycommand.sed                                                               
#

/^BEGIN/, /^END/ {
    s/[Ll]inux/GNU\/Linux/g
    s/[Oo]penbsd/OpenBSD/g
    s/[Ff]reebsd/FreeBSD/g
    s/[Nn]etBSD/NetBSD/g
}


<emphasis>USAGE :</emphasis>

$ sed -n -f ~/mycommand.sed myfile.txt &gt; res.txt

</programlisting></para>
    </sect2>

    <sect2>
      <title>Exercices</title>

      <simplesect>
        <title>Exercice 1</title>

        <para>Créez un nouveau répertoire
        <filename>~/elementBase/part3</filename>/. Copiez y le fichier
        <filename>ps-aux</filename> que nous avions utilisé lors de la
        dernière séance.</para>

        <formalpara>
          <title>Travail à  faire</title>

          <para></para>
        </formalpara>

        <orderedlist>
          <listitem>
            <para>Supprimer les processus dont le propriétaire est<command>
            root</command>, et placez le résultat dans
            <filename>my_ps-aux</filename></para>
          </listitem>

          <listitem>
            <para>Modifiez le nom du propriétaire <command>sysop</command>, en
            le remplaçant par le votre. Le résultat est placé dans
            <filename>my_ps-aux</filename></para>
          </listitem>

          <listitem>
            <para>Supprimez les éventuels chemins des exécutables.
            (<filename>/bin/tcsh</filename> deviendra
            <filename>tcsh</filename>)</para>
          </listitem>
        </orderedlist>
      </simplesect>

      <simplesect>
        <title>Exercice 2</title>

        <para>On dispose d'un répertoire web contenant des fichiers html, pour
        lesquels on voudrait changer toutes les occurences des images au
        format gif par des images identiques au format png.</para>

        <formalpara>
          <title>Travail à  faire</title>

          <para>Proposer un script qui effectue ces changements dans tous les
          fichiers. On sauvegardera de plus tous les anciens fichiers dans un
          sous-repértoire nommé BAK.</para>
        </formalpara>

        <formalpara>
          <title>Proposition de correction</title>

          <para>On se place dans le repertoire cible. <programlisting
          width="80">
<emphasis>SCRIPT SHELL (sh) :</emphasis>

if [ ! -d BAK ]; then mkdir BAK; fi &amp;&amp; \                                        
for f in `find . -name "*.htm[l]" -print`; do
  cp $f BAK
  sed -e 's/.gif/.png/g' &lt; $f &gt; $f.tmp
  mv $f.tmp $f
done

</programlisting></para>
        </formalpara>
      </simplesect>
    </sect2>
  </sect1>

  <sect1 id="id_awk">
    <title>Eléments d'initiation à  awk</title>

    <para><command>awk</command> est un langage de script particulièrement
    intéressant dans l'analyse et le traitement de fichier texte ainsi que
    dans la génération de rapports. Nous présentons dans cette partie ces
    principales caractéristiques sur des exemples.</para>

    <sect2 id="awk_ex1">
      <title>Premier exemple</title>

      <para>On suppose vouloir extraire du fichier
      <filename>/etc/passwd</filename> les <emphasis>uids</emphasis>,
      <emphasis>gids</emphasis> et nom d'utilisateur, le tout trié en majeur
      sur l'<emphasis>uid</emphasis> et en mineur sur le
      <emphasis>gid</emphasis>. Bien entendu, les lignes de commentaires ne
      doivent pas apparaître. Voilà  typiquement un travail pour
      <command>awk</command>.</para>

      <para><programlisting width="80">
<emphasis>EXEMPLE :</emphasis>

$ awk -F":" '$0 !~ /^#/ { print $3"\t"$4"\t"$1 }' /etc/passwd | sort -n -k 1,2  
0       0       root
0       0       toor
1       1       daemon
2       5       operator
3       7       bin
4       65533   tty
5       65533   kmem
7       13      games
8       8       news
9       9       man
22      22      sshd
25      25      smmsp
26      26      mailnull
53      53      bind
66      66      uucp
67      67      xten
68      6       pop
70      70      pgsql
80      80      www
88      88      mysql
666     666     pascal
65534   65534   nobody

</programlisting> L'option <option>-F</option> de l'interpréteur
      <command>awk</command> permet de spécifier le séparateur de champ, ici
      le caractère <quote>:</quote>. Le reste dit que si la ligne dénotée par
      $0 ne commence pas par le caractère # (c'est la syntaxe de
      <emphasis>csh</emphasis>, <abbrev>i.e.</abbrev> du langage
      <emphasis>C</emphasis>) alors on imprime sur la sortie standard les
      trois champs dénotés $3, $4 puis $1 (désignant respectivement
      l'<emphasis>uid</emphasis>, le <emphasis>gid</emphasis> et le nom
      d'utilisateur), lesquels sont repris en entrée de la commande
      <command>sort</command> qui trie numériquement (option
      <option>-n</option>) respectivement sur les champs positionnels 1 et 2
      (<abbrev>i.e.</abbrev> l'<emphasis>uid</emphasis> et le
      <emphasis>gid</emphasis>). Noter enfin, l'utilisation des quotes qui
      permet d'empêcher l'évaluation des variables $0, $1, $3 et $4 par le
      <emphasis>shell</emphasis>.</para>

      <para>L'utilisation de <command>awk</command> ne se limite pas aux
      scripts à  une ligne (les fameux
      <foreignphrase>one-liners</foreignphrase>), c'est un véritable langage
      de programmation doté de structures de contrôles et manipulant des
      variables.</para>
    </sect2>

    <sect2>
      <title>Scripts externes</title>

      <para>Si le code du script <command>awk</command> devient complexe et/ou
      s'étend sur plusieurs lignes, il est possible de le mettre dans un
      fichier indépendant. Pour l'invoquer ensuite il suffit de passer
      l'option <option>-f</option> à  l'interpréteur, comme suit :
      <programlisting width="80">
<emphasis>EXEMPLE :</emphasis>

$ awk -f myscript.awk &lt;fichier_à _traiter&gt;                                       

</programlisting></para>

      <simplesect>
        <title>Blocs d'instructions</title>

        <para>La structure typique d'un script <command>awk</command> est
        composé de trois blocs : <programlisting width="80">
<emphasis>STRUCTURE D'UN SCRIPT <command>awk</command> :</emphasis>

BEGIN {
  # bloc spécial d'initialisation, facultatif, exécuté avant que awk ne commence
  # à  traiter le fichier d'entrée &lt;fichier_à _traiter&gt; 
}
{
  # bloc de code exécuté à  chaque ligne du fichier &lt;fichier_à _traiter&gt; 
}
END {
  # bloc spécial de terminaison, facultatif, exécuté après que awk ait terminé
  # le traitement du fichier d'entrée &lt;fichier_à _traiter&gt; 
}

</programlisting> Toute ce qui suit le caractère # est considéré comme un
        commentaire qui est ignoré par l'interprète
        <command>awk</command>.</para>

        <para>Si nous reprenons sous forme de script externe, le
        <foreignphrase>one-liners</foreignphrase> précédent
        (<abbrev>c.f.</abbrev> <xref linkend="awk_ex1" />), cela peut donner :
        <programlisting width="80">
<emphasis>CODE :</emphasis>

# ~/bin/myscript1.awk                                                           

BEGIN {
# block d'initialisation                                                
  FS=":"     # Field Separator        : positionné à  ":"
  OFS="\t"   # Output Field Separator : positionné à  "\t"
}
{
# block d'execution
  if ( $0 !~ /^#/ ) {
    print $3,$4,$1
  }
}
END {
# block final
}

<emphasis>UTILISATION :</emphasis>

$ awk -f ~/bin/myscript1.awk /etc/passwd | sort -n -k 1,2

</programlisting></para>

        <formalpara>
          <title>Exemple 2</title>

          <para>Autre exemple, trouver l'<emphasis>uid</emphasis> maximum dans
          le fichier <filename>/etc/passwd</filename> et l'afficher ainsi que
          le nom de login et le <emphasis>gid</emphasis> du groupe
          correspondant. <programlisting width="80">
<emphasis>CODE :</emphasis>

# ~/bin/myscript2.awk                                                           

BEGIN {
# block d'initialisation                                    
  FS=":"     # Field Separator        : positionné à  ":"
  OFS="\t"   # Output Field Separator : positionné à  "\t"
  uid=0
  gid=0
  name=""
}
{
# block d'execution - recherche de l'uid et du gid maximun
  if ( $0 !~ /^#/ ) {
       if ( $3 &gt; uid ) {
 uid=$3
 gid=$4
 name=$1
       }
  }
}
END {
# block final
  print "nom = ", name, "uid max = ", uid, "gid = ", gid 
}

<emphasis>UTILISATION :</emphasis>

$ awk -f ~/bin/myscript2.awk /etc/passwd 
nom =   nobody  uid max =       65534   gid =   65534

</programlisting></para>
        </formalpara>

        <formalpara>
          <title>Example 3</title>

          <para>La commande <command>ps aux</command> permet sur un système
          <emphasis>BSD</emphasis> d'obtenir par processus, entre autre, la
          taille de la mémoire virtuelle utilisée (champs
          <emphasis>vsz</emphasis>) ainsi que la taille de la mémoire réelle
          utilisée (champs <emphasis>rss</emphasis>), l'unité étant le
          kilo-octet. On désire avoir le total pour ces deux paramètres tous
          processus confondus. <programlisting width="80">
<emphasis>CODE :</emphasis>

# ~/bin/mypstot.awk                                                             

BEGIN {
# block d'initialisation
  FS=" "
  totvsz = 0
  totrss = 0
}
{
# block d'execution
  if ( $0 !~ /^USER/ ) {
    totvsz += $5 
    totrss += $6
  }
}
END {
# block final
  printf("Total VSZ = %6d\t\ttotal RSS = %6d\n", totvsz, totrss)
}

<emphasis>UTILISATION :</emphasis>

$ ps aux | awk -f ~/bin/mypstot.awk
Total VSZ = 876712              total RSS = 701040

</programlisting></para>
        </formalpara>
      </simplesect>

      <simplesect>
        <title>Expressions régulières, conditionnelles, structure condionnelle
        et blocs exécutables</title>

        <para><command>awk</command> permet l'exécution conditionelle d'un
        bloc. Il suffit pour cela de préfixer le bloc à  exécuter par une
        expression à  valeur booléenne, <abbrev>i.e.</abbrev> la chaîne vide et
        l'entier 0 sont interprétés comme la valeur booléenne
        <quote>faux</quote>, le reste est <quote>vrai</quote>.</para>

        <formalpara>
          <title>Les expressions régulières (ou rationnelles)</title>

          <para><programlisting width="80">
<emphasis>EXEMPLES :</emphasis>

/^root/ { print }      # n'imprime que les lignes commençant par le motif root  

/csh$/ { print }       # n'imprime que les lignes finissant par le motif csh

/[0-9]+:[A-Za-z]*/ { print }       
                       # n'imprime que les lignes contenant un motif structuré 
                       # ainsi entier puis ":" puis chaîne de caractères

! /root/ { print }     # n'imprime que les lignes ne contenant pas le motif root

</programlisting></para>
        </formalpara>

        <formalpara>
          <title>Les expressions conditionnelles</title>

          <para><programlisting width="80">
<emphasis>EXEMPLES :</emphasis>

$1 == "pascal" { print } # (1) imprime la ligne si le premier champ est égale à  
                         # "pascal" (égalité de chaîne de caractères)

$5 !~ /root/ { print }   # (2) imprime la ligne si le 5e champ ne contient pas l
                         # motif root 

( $1 == "foo" ) &amp;&amp; ( $3 &gt; 666 ) { print }       
                         # (3) imprime la ligne corresp. si le 1er champ est une 
                         # chaîne égale à  "foo" et le 3e champ un entier plus
                         # grand strictement à  666

</programlisting></para>
        </formalpara>

        <formalpara>
          <title>La structure conditionnelles</title>

          <para><command>awk</command> offre l'instruction
          <command>if</command>. Tous les exemples pécédents peuvent ainsi
          être réécrit. <programlisting width="80">
<emphasis>EXEMPLES :</emphasis>

{                           # reprise du (1) précédent                          
  if ( $1 == "pascal" ) {   
     print
  }
}

{                           # reprise du (2)
  if ( $5 !~ /root/ ) {     
     print
  }
}

{                           # reprise du (3)
  if ( ( $1 == "foo" ) &amp;&amp; ( $3 &gt; 666 ) ) {
     print
  }
}

</programlisting></para>
        </formalpara>
      </simplesect>

      <simplesect>
        <title>Boucles</title>

        <!-- <para>&todo; for, while, break, continue</para> -->

        <formalpara>
          <title>boucle <command>while</command></title>

          <para><programlisting width="80">
<emphasis>EXEMPLE :</emphasis>

#
# ~/bin/test.awk
#
BEGIN {                                                                         
  FS=":"
  ORS="\t"
  nbfield=0
}
{
  x = 1
  while ( x &lt; NF ) {  # NF var. spéciale donnant le nombre de champs (Number of 
    print $x          # Fields) de la ligne courante
    x++
  }
  print NF, " champs lus \n" 
  nbfield += NF
} 
END {
  print "\ttotal : ", nbfield, " champs lus \n" 
}


<emphasis>UTILISATION :</emphasis>

$ awk -f ~/bin/test.awk /etc/group
# $FreeBSD       src/etc/group,v 1.19.2.3 2002/06/30 17 57      4  champs lus 
        1  champs lus 
        wheel   *       0       4  champs lus 
        daemon  *       1       4  champs lus 
        kmem    *       2       4  champs lus 
        sys     *       3       4  champs lus 
        tty     *       4       4  champs lus 
        operator        *       5       4  champs lus 
        mail    *       6       4  champs lus 
        bin     *       7       4  champs lus 
        news    *       8       4  champs lus 
        man     *       9       4  champs lus 
        staff   *       20      4  champs lus 
        sshd    *       22      4  champs lus 
        smmsp   *       25      4  champs lus 
...
         total :  137  champs lus 

</programlisting></para>
        </formalpara>

        <formalpara>
          <title>boucle <command>do ... while</command></title>

          <para>Ici, l'évaluation de la condition se fait après la fin de la
          boucle. <programlisting width="80">
<emphasis>EXEMPLE :</emphasis>

#
# ~/bin/test2.awk                                                               
#
BEGIN {                                                                         
  FS=":"
  ORS="\t"
  nbfield=0
}
{
  x = 1
  do {
    print $x          
    x++
  } while ( x &lt; NF )
  print NF, " champs lus \n" 
  nbfield += NF
} 
END {
  print "\ttotal : ", nbfield, " champs lus \n" 
}


<emphasis>UTILISATION :</emphasis>

$ awk -f ~/bin/test2.awk /etc/group
# $FreeBSD       src/etc/group,v 1.19.2.3 2002/06/30 17 57      4  champs lus 
        #       1  champs lus 
        wheel   *       0       4  champs lus 
        daemon  *       1       4  champs lus 
        kmem    *       2       4  champs lus 
        sys     *       3       4  champs lus 
        tty     *       4       4  champs lus 
        operator        *       5       4  champs lus 
        mail    *       6       4  champs lus 
        bin     *       7       4  champs lus 
        news    *       8       4  champs lus 
        man     *       9       4  champs lus 
...
                total :  117  champs lus 

</programlisting></para>
        </formalpara>

        <formalpara>
          <title>boucle <command>for</command></title>

          <para><programlisting width="80">
<emphasis>EXEMPLE :</emphasis>

#
# ~/bin/test3.awk                                                               
#
BEGIN {                                                                         
  FS=":"
  ORS="\t"
  nbfield=0
}
{
  for ( x = 1; x &lt; NF; x++ ) {  
    print $x          
  } 
  print NF, " champs lus \n" 
  nbfield += NF
} 
END {
  print "\ttotal : ", nbfield, " champs lus \n" 
}


<emphasis>UTILISATION :</emphasis>

$ awk -f ~/bin/test3.awk /etc/group
# $FreeBSD       src/etc/group,v 1.19.2.3 2002/06/30 17 57      4  champs lus 
        #       1  champs lus 
        wheel   *       0       4  champs lus 
        daemon  *       1       4  champs lus 
        kmem    *       2       4  champs lus 
        sys     *       3       4  champs lus 
        tty     *       4       4  champs lus 
        operator        *       5       4  champs lus 
        mail    *       6       4  champs lus 
        bin     *       7       4  champs lus 
        news    *       8       4  champs lus 
        man     *       9       4  champs lus  
...
                total :  117  champs lus 

</programlisting></para>
        </formalpara>

        <formalpara>
          <title>instructions <command>break</command> et
          <command>continue</command></title>

          <para>Ces deux intructions permmettent de <quote>rompre</quote> le
          déroulement classique d'une boucle. La première permet de sortir
          (inconditionnellement quand elle est rencontrée) du corps de la
          boucle la plus interne. La seconde, quant à  elle, relance une
          nouvelle itération en <quote>shuntant</quote> littérallement le
          reste du code de la boucle. <programlisting width="80">
<emphasis>EXEMPLE :</emphasis>

#                                                                               
# ~/bin/test4.awk 
#
{
  i = 1
  while (1) { # boucle infinie
     # 'continue' conduit ici
     if ( ( i % 4 ) == 0 ) {
        i++
        continue
     }
     print "iteration " i
     if ( i &gt; 20 ) {
        break
     }
     i++
  }
  # 'break' conduit là 
  print "termine : " i
}


<emphasis>UTILISATION :</emphasis>

$ awk -f ~/bin/test4.awk 

&lt;ENTREE&gt;
iteration 1
iteration 2
iteration 3
iteration 5
iteration 6
iteration 7
iteration 9
iteration 10
iteration 11
iteration 13
iteration 14
iteration 15
iteration 17
iteration 18
iteration 19
iteration 21
termine : 21
^C

</programlisting></para>
        </formalpara>
      </simplesect>

      <simplesect>
        <title>Type de variables</title>

        <para>Il existe deux types scalaires : les entiers et les chaines de
        caractères (vus dans les exemples précédents) et un type structuré :
        tableau.</para>

        <para>Attention, contrairement au langage <emphasis>C</emphasis> une
        chaîne de caractères n'est pas un tableau de caractères.</para>
      </simplesect>

      <simplesect>
        <title>Opérateurs</title>

        <para>Il s'agit des opérateurs du langages C.</para>
      </simplesect>

      <simplesect>
        <!--Added Ivan Kurzweg 05/03/2006-->

        <title>Fonctions</title>

        <para>AWK met à  la disposition du programmeur des fonctions standard
        prédéfinies, dont voici quelques unes :</para>

        <itemizedlist>
          <listitem>
            <para><command>length(chaine)</command> : donne la longueur de son
            argument, par défaut $0</para>
          </listitem>

          <listitem>
            <para><command>substr(chaine_1,int_1,int_2)</command> : donne la
            sous chaine de chaine_1 commençant à  la position int_1 et de
            longueur inférieure ou égale à  int_2</para>
          </listitem>

          <listitem>
            <para><command>split(chaine, tab, car)</command>: éclate la
            chaine, les sous chaine sont récupérées en tab[1], tab[2]... Le
            caractère car sert à  délimmiter les différents morceaux.</para>
          </listitem>

          <listitem>
            <para><command>index(chaine_1, chaine_2)</command>: donne la
            position de la premiere occurence de chaine_2 dans
            chaine_1.</para>
          </listitem>
        </itemizedlist>
      </simplesect>

      <simplesect>
        <title>Variables spéciales</title>

        <para>Il existe des variables prédéfinies dans awk, les voici :</para>

        <itemizedlist>
          <listitem>
            <para><command>FS</command> : séparateur de champ dans le fichier
            (par défaut espace ou tabulation), un nombre quelconque de
            séparateur étant équivalent à  un seul. L'option -F permet de
            modifier à  l'appel de la commande la valeur de ce
            séparateur.</para>
          </listitem>

          <listitem>
            <para><command>RS</command> : séparateur d'enregistrement en
            entrée dans le fichier (par défaut le caractère de fin de ligne,
            un enregistrement étant alors une ligne)</para>
          </listitem>

          <listitem>
            <para><command>OFS</command> : séparateur de champ en sortie (par
            défaut espace)</para>
          </listitem>

          <listitem>
            <para><command>ORS</command> : séparateur d'enregistrement en
            sortie (par défaut le caractère fin de ligne)</para>
          </listitem>

          <listitem>
            <para><command>NF</command> : nombre de champ de l'enregistrement
            courant</para>
          </listitem>

          <listitem>
            <para><command>NR</command> : numéro de l'enregistrement en cours
            de traitement</para>
          </listitem>

          <listitem>
            <para><command>FILENAME</command> : nom du fichier en cours de
            traitement</para>
          </listitem>
        </itemizedlist>
      </simplesect>

      <!--End added-->

      <simplesect>
        <title>Variables de type tableaux</title>

        <para>Ce type structuré permet de stocker différents éléments (de type
        différents dans une structure <quote>naturellement</quote> indéxée par
        des chaînes de caractères. Tous les tableaux <command>awk</command>
        sont donc des tableaux associatifs, y compris ceux indexé par des
        entiers, puisqu'en <command>awk</command> un entier est représenté par
        sa chaîne.</para>

        <para>La simple déclaration suivante, permet de définir un tableau :
        <programlisting width="80">
<emphasis>EXEMPLE :</emphasis>

myarr[0] = "World"
myarr[1] = 72
myarr[2] = "Hello"                                                               

</programlisting> L'origine de l'indexation à  0 ou à  1 est laissé au libre
        choix du programmeur, <command>awk</command> ne pose aucun problème.
        La construction suivante permet d'itérer sur le contenu du tableau :
        <programlisting width="80">
<emphasis>EXEMPLE :</emphasis>

for ( i in myarr ) {                                                            
   print myarr[i]
}

</programlisting> Toutefois, il n'y a aucune garantie sur l'ordre
        d'impression.</para>

        <para>Suppression [<command>delete</command>] d'éléments dans un
        tableau : <programlisting width="80">
<emphasis>EXEMPLE :</emphasis>

delete myarr[1] # suppression de l'éléments indexé par l'entier 1               

</programlisting></para>

        <para>appartenance d'un élément à  un tableau [<command>in</command>] :
        <programlisting width="80">
<emphasis>EXEMPLE :</emphasis>

{                                                                               
  elem=72
  if ( elem in myarr ) {
     ...
  }
  else {
     ...
  }
  ...
}

</programlisting></para>
      </simplesect>
    </sect2>

    <sect2>
      <title>Exercices</title>

      <simplesect>
        <title>Exercice 1</title>

        <para>On dispose de différents fichiers à  la structure identique : une
        première ligne non pertinente qui pourra être ignorée, suivi d'un
        ensemble de lignes structurées en 13 champs séparés soit par des
        caractères espaces, soit par des caractères de tabulation. Voici un
        exemple de ligne :</para>

        <para><computeroutput>str1 int2 int3 int4 int5 int6 int7 int8 int9
        int10 int11 int12 int13</computeroutput></para>

        <formalpara>
          <title>Travail à  faire</title>

          <para>On souhaiterait faire la somme des colonnes de chacun des
          fichiers et écrire les résultats obtenus dans un fichier résultat,
          au format suivant : <computeroutput>file_i tot2 tot3 tot4 tot5 tot6
          tot7 tot8 tot9 tot10 tot11 tot12 tot13</computeroutput>. On pourra
          supposer que chaque fichier dispose d'une marque explicite de fin
          (ici &lt;&lt;EOF&gt;&gt;).</para>
        </formalpara>

        <formalpara>
          <title>Réponse :</title>

          <para><programlisting width="80">
<emphasis>CODE :</emphasis>

BEGIN {
  # Proposition de Correction - Les fichiers possèdent une marque spéciale de   
  # fin : &lt;&lt;EOF&gt;&gt;

  FS= " "     # Field Separator

  OFS = "\t"
  ORS = ""
  RT = "^D"
 
  MAX=12  
  for ( i=0; i &lt; MAX; i++ ) {
    mysum[i] = 0
    mytot[i] = 0
  }
}

{
  if ( $0 ~ /^&lt;&lt;EOF&gt;&gt;$/ ) {
    # Afficher les totaux des stats du fichier 
    print FILENAME, " "
    for ( i=0; i &lt; MAX; i++ ) {
      printf("%5s", mysum[i])
    }
    print "\n";  
      
    # (re)initialiser le tableau 
    for ( i=0; i &lt; MAX; i++ ) {
      mysum[i] = 0
    }  
  }
  else {
   # totaliser
   for ( i=0; i &lt; MAX; i++ ) {
      mysum[i] += $(i+2)
      mytot[i] += $(i+2)
   }
  }
}

END {
  print "TOTAL", " "
  for ( i=0; i &lt; MAX; i++ ) {
    printf("%5s", mytot[i])
  }
  print "\n";
}

<emphasis>UTILISATION :</emphasis>

$ awk -f sumstat.awk stat1 stat2 stat3
stat1        5    6    5    6    5    6    6    7    6    5    4    6
stat2        5    6    5    6    5    6    6    7    6    5    4    6
stat3       14   15    5    6    5   15    6    7    6    5   13    6
TOTAL       24   27   15   18   15   27   18   21   18   15   21   18

</programlisting></para>
        </formalpara>
      </simplesect>

      <simplesect>
        <title>Exercice 2</title>

        <formalpara>
          <title>Travail à  faire</title>

          <para>Récupérer l'adresse IP et MAC des interfaces réseaux de votre
          machine en utilisant les valeurs données par la commande
          <command>ifconfig</command></para>
        </formalpara>
      </simplesect>

      <simplesect>
        <title>Exercice 3</title>

        <formalpara>
          <title>Travail à  faire</title>

          <para>Simuler (en partie) avec un script <command>awk</command> la
          commande <command>wc</command> (<foreignphrase>word
          count</foreignphrase>), qui sans option supplémentaire donne
          respectivement le nombre de ligne(s), de mot(s) (relativement à  un
          séparateur prédéfini), d'octet(s) du fichier qui lui est passé en
          argument.</para>
        </formalpara>

        <formalpara>
          <title>Réponse : Simuler <command>wc</command></title>

          <para><programlisting width="80"> 
<emphasis>CODE :</emphasis>

# ~/bin/wc.awk                                                                  

BEGIN {
# block d'initialisation                                    
  RS="\n"     # Record Separator   
  OFS="\t"    # Output Field Separator

  line=0      # var. utilisateur  
  word=0
  byte=0
}
{
# block d'execution - comptabiliser le nombre de ligne, mot, octet
    line++
    word += NF
    byte += length($0) + 1   # donne la longueur de la ligne au complet
}
END {
# block final
  print "", line, word, byte, FILENAME
}

<emphasis>UTILISATION :</emphasis>

$ wc /etc/passwd     # la commande originale                                    
       29      79    1589 /etc/passwd

$ awk -f ~/bin/wc.awk /etc/passwd
        29      79      1589    /etc/passwd

$ wc /etc/motd       # la commande originale
      24     154    1074 /etc/motd

$ awk -f ~/bin/wc.awk /etc/motd
       24      154     1074    /etc/motd

</programlisting></para>
        </formalpara>
      </simplesect>

      <simplesect>
        <title>Exercice 4</title>

        <formalpara>
          <title>Travail à  faire</title>

          <para>Reprenons le fichier my_ps obtenu dans le chapitre précédent.
          </para>
        </formalpara>

        <itemizedlist>
          <listitem>
            <para>Affichez le total de l'occupation de la mémoire de vos
            processus (somme des <abbrev>VSZ</abbrev>)</para>
          </listitem>

          <listitem>
            <para>Donnez le <acronym>PID</acronym> du programme le plus
            gourmand en mémoire (<abbrev>%MEM</abbrev>)</para>
          </listitem>

          <listitem>
            <para>Remplacez les heures "anglaises" en leur équivalent
            "français"</para>
          </listitem>
        </itemizedlist>
      </simplesect>
    </sect2>
  </sect1>


 <sect1>
    <title>Exercices de synthèse</title>

 <sect2>
    <title>Commandes et notions de bases</title>

    <sect3>
      <title>Exercices commandes et redirection</title>

      <orderedlist>
        <listitem>
          <para>Indiquez la commande pour afficher les lignes de 10 à  25 d'un
          fichier.</para>
        </listitem>

        <listitem>
          <para>Exécutez la commande : <command>yes toto | head -200 | split
          -5</command> . Expliquer le résultat obtenu en vous aidant du
          <command>man</command>.</para>
        </listitem>

        <listitem>
          <para>Tout en restant dans le répertoire où vous avez exécuté la
          commande précédente, indiquez les commandes permettant de :</para>

          <itemizedlist>
            <listitem>
              <para>lister le contenu du répertoire</para>
            </listitem>

            <listitem>
              <para>lister les fichiers dont le nom fini par 'e'</para>
            </listitem>

            <listitem>
              <para>lister les fichiers dont le nom contient un 'a'</para>
            </listitem>

            <listitem>
              <para>lister les fichiers dont le nom se termine par une lettre
              comprise en 'c' et 'g'</para>
            </listitem>

            <listitem>
              <para>lister les fichiers dont le nom ne se termine pas par une
              lettre comprise en 'c' et 'g'</para>
            </listitem>

            <listitem>
              <para>lister les fichiers dont le nom a un 'b' en deuxième
              position mais pas en troisième position</para>
            </listitem>
          </itemizedlist>
        </listitem>

        <listitem>
          <para>Donnez la séquence de commandes la plus courte permettant de
          déplacer tous les fichier dont le nom contient un 'a' vers le
          répertoire
          <filename>~/elementBase/synthese/exo/toto/fic/liste/a/</filename></para>
        </listitem>
      </orderedlist>
    </sect3>
  </sect2>

  <sect2>
    <title>Sed et Awk .. et autres !</title>

    <sect3>
      <title>Conversions de monnaies</title>

      <simplesect>
        <title></title>

        <formalpara>
          <title></title>

          <para>A partir du fichier de monnaies (<ulink
          url="./euro.txt">euro.txt</ulink>),</para>
        </formalpara>

        <itemizedlist>
          <listitem>
            <para>Afficher la liste des pays et de leur monnaies, une paire
            par ligne, chaque pays précédant sa monnaie et en étant séparé par
            un `:'</para>
          </listitem>

          <listitem>
            <para>Trouver la valeur de la monnaie la plus forte</para>
          </listitem>
        </itemizedlist>
      </simplesect>
    </sect3>

    <sect3>
      <title>Traitements de domaines internet</title>

      <para>Dans le cadre de la mise en place d'une connexion Internet
      filtrée, vous devez traiter régulièrement des fichiers de noms de
      domaines interdits. Dans cet exercice, vous allez devoir travailler sur
      des domaines diffusant de la publicité. Un premier exemple de fichier
      est téléchargeable sur <ulink
      url="./domains.txt">domains.txt</ulink>.
      Téléchargez ce fichier dans votre répertoire
      <filename><filename>~/elementBase/synthese/exo2/</filename></filename>,
      et faites en une copie sous le nom
      <filename>dom_orig.txt</filename></para>

      <orderedlist>
        <listitem>
          <para>Certaines URLs possèdent des informations de ports. Le réseau
          empêchant déjà  les connections Web vers des ports autres que le port
          80, vous devez supprimer l'ensemble des ports (les informations
          précédées de '<computeroutput>:'</computeroutput>). De la même
          manière, vous devez supprimer les informations concernant les
          protocoles utilisés (<command>http://, ftp://,</command> ...)</para>
        </listitem>

        <listitem>
          <para>Les traitements sur les adresses IP et sur les noms de
          domaines étant sensiblement différents, vous devez séparer le
          fichier en deux fichiers, l'un contenant les adresses "<emphasis>en
          dur</emphasis>", l'autre les domaines nommés.</para>
        </listitem>

        <listitem>
          <para>Vous cherchez maintenant à  simplifier certaines URLs, en
          supprimant les informations de machines sur les sous-domaines.
          Typiquement vous devez arriver à  une liste de type<emphasis>
          <computeroutput><classname>sousdomaine.domaine</classname></computeroutput></emphasis>.</para>
        </listitem>

        <listitem>
          <para>Le filtrage actuel contient déjà  une vérification sur les mots
          clefs, en particulier, il interdit toutes les URLs qui contiennent
          le champ '<command>ads</command>' (attention, pas la sous chaine
          '<command>ads</command>'). Modifier le fichier en
          conséquence.</para>
        </listitem>

        <listitem>
          <para>Votre fichier est prêt à  être exploité, mais il reste à 
          l'optimiser après toutes les manupulations que vous avez faites.
          Retriez le fichier et supprimez les doublons. Trier les noms de
          domaines par domaines (.org, .com, ...).</para>
        </listitem>

        <listitem>
          <para>Enfin, vous serez amener à  réaliser cette procédure de
          nombreuses fois... Automatisez totalement les traitements, en
          affcihant pour chaque étape les informations qui vous semblent
          pertinentes (nombres de lignes modifiées, etc..). Au final, le
          programme devra donner le nombre d'adresses IP retenues, et le
          nombre de sous domaines par domaine.</para>
        </listitem>
      </orderedlist>
    </sect3>
  </sect2>
</sect1>
  <!-- VERSION ASR FIN -->

  <bibliography>
    <title>Références</title>

    <bibliodiv>
      <biblioentry>
        <abbrev>1</abbrev>

        <authorgroup>
          <author>
            <personname>
              <firstname>Robbins</firstname>

              <surname>Daniel</surname>
            </personname>

            <email>drobbins@gentoo.org</email>
          </author>
        </authorgroup>

        <title>LPI Certification 101 exam prep, part 1</title>

        <edition><ulink
        url="http://www-106.ibm.com/developerworks/edu/l-dw-linux-lpir21-i.html"></ulink></edition>
      </biblioentry>

      <biblioentry>
        <abbrev>2</abbrev>

        <authorgroup>
          <author>
            <personname>
              <firstname>Robbins</firstname>

              <surname>Daniel</surname>
            </personname>

            <email>drobbins@gentoo.org</email>
          </author>

          <author>
            <personname>
              <firstname>Houser</firstname>

              <surname>Chris</surname>
            </personname>
          </author>

          <author>
            <personname>
              <firstname>Griffis</firstname>

              <surname>Aron</surname>
            </personname>
          </author>
        </authorgroup>

        <title>LPI Certification 101 exam prep, part 2</title>

        <edition><ulink
        url="http://www-106.ibm.com/developerworks/edu/l-dw-linux-lpir22-i.html"></ulink></edition>
      </biblioentry>

      <!-- VERSION ASR DEBUT -->

      <biblioentry>
        <abbrev>3</abbrev>

        <authorgroup>
          <author>
            <personname>
              <firstname>Dougherty</firstname>

              <surname>Dale</surname>
            </personname>
          </author>

          <author>
            <personname>
              <firstname>Robbins</firstname>

              <surname>Arnold</surname>
            </personname>
          </author>
        </authorgroup>

        <title>sed &amp; awk, 2nd Edition</title>

        <isbn>1-56592-225-5</isbn>

        <date>March 1997</date>

        <publisher>
          <publishername>O'Reilly</publishername>
        </publisher>

        <edition><ulink
        url="http://www.oreilly.com/catalog/sed2/"></ulink></edition>
      </biblioentry>

      <biblioentry>
        <abbrev>4</abbrev>

        <authorgroup>
          <author>
            <personname>
              <firstname>Robbins</firstname>

              <surname>Daniel</surname>
            </personname>

            <email>drobbins@gentoo.org</email>
          </author>
        </authorgroup>

        <title>Common threads : Awk by example, Part 1 - an intro to the great
        language with the strange name</title>

        <edition><ulink
        url="http://www-106.ibm.com/developerworks/linux/library/l-awk1.html"></ulink></edition>
      </biblioentry>

      <biblioentry>
        <abbrev>5</abbrev>

        <authorgroup>
          <author>
            <personname>
              <firstname>Robbins</firstname>

              <surname>Daniel</surname>
            </personname>

            <email>drobbins@gentoo.org</email>
          </author>
        </authorgroup>

        <title>Common threads : Awk by example, Part 2 - Records, loops and
        arrays</title>

        <edition><ulink
        url="http://www-106.ibm.com/developerworks/linux/library/l-awk2.html"></ulink></edition>
      </biblioentry>

      <biblioentry>
        <abbrev>6</abbrev>

        <authorgroup>
          <author>
            <personname>
              <firstname>Robbins</firstname>

              <surname>Daniel</surname>
            </personname>

            <email>drobbins@gentoo.org</email>
          </author>
        </authorgroup>

        <title>Common threads : Awk by example, Part 3 - String functions and
        ...</title>

        <edition><ulink
        url="http://www-106.ibm.com/developerworks/linux/library/l-awk3.html"></ulink></edition>
      </biblioentry>

      <!-- VERSION ASR FIN -->
    </bibliodiv>
  </bibliography>
</article>

