<?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 ccdil "ç">
<!ENTITY organ "Néotech III">

<!ENTITY unix   "<productname>Unix</productname>">
<!ENTITY Unix   "<emphasis>Unix</emphasis>">

<!ENTITY bsd    "<emphasis>BSD</emphasis>">
<!ENTITY ie     "<abbrev>i.e.</abbrev>">
<!ENTITY cf     "<abbrev>c.f.</abbrev>">
<!ENTITY shell  "<foreignphrase>shell</foreignphrase>">
<!ENTITY todo   "<command>--- T O  D O :</command>">

<!ENTITY fshell "<emphasis>csh</emphasis>">
<!ENTITY fshell2 "<emphasis>tcsh</emphasis>">

<!ENTITY _fcomp  SYSTEM "./fcomp.sh.2">
<!ENTITY _fdate  SYSTEM "./fdate.sh">
<!ENTITY _ftestp SYSTEM "./ftestparm.sh">
<!ENTITY _ftestv SYSTEM "./ftestvect.sh.2">

<!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éunion</address></affiliation>">
<!ENTITY _holder      "<holder>Pascal PICARD, <emphasis>pascal@seth.homeunix.net</emphasis></holder>"> 
]>

<article class="techreport" lang="fr" >
  <articleinfo>


    <author>
<firstname>Ivan</firstname>">
<surname>Kurzweg</surname>
    </author>
    <title> Csh &amp; TCsh</title>
    <copyright>
      <holder>Ivan Kurzweg , Pascal Picard </holder>
      <year>2002 - 2006</year>
    </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>
Ce cours est largement inspiré du cours de Pascal Picard disponible sur https://seth.homeunix.net/corto</para>

    </legalnotice>

    <keywordset>
      <keyword>interprète de commande, shell, csh, tcsh, completion, historique</keyword>
    </keywordset>
  </articleinfo>
  
  <abstract>
    <para>Le &shell; est d'abord l'interpréteur de commande d'un système &unix; mais c'est aussi un quasi langage de programmation interpreté autorisant la récursivité.
</para> 
    <para> Historiquement le premier &shell; du système &unix; est le <application>Bourne-Shell</application> (<command>sh</command>). Ce &shell; n'a cessé d'être amélioré et l'université de Berkeley qui a beaucoup contribué à la branche <emphasis><abbrev>BSD</abbrev></emphasis> d'&unix; a développé le <application>C-Shell</application> (<command>&fshell;</command>), un successeur de <command>sh</command> munit de fonctionnalités étendues par rapport à son ancêtre. 
Le <application>C-Shell</application> à son tour possède un successeur : <application>TC-Shell</application> (<command>tcsh</command>), ce dernier étend les fonctionnalités de son prédécesseur et apporte davantage de convivialité. Ces caractéristiques en font un équivalent au <application>GNU Bourne-Again-Shell</application> (<command>GNU/bash</command>).
</para> 

<para> Ces <foreignphrase>shells</foreignphrase> syntaxiquement orientés <command>C</command> restent les shells par défaut des <foreignphrase>flavors</foreignphrase> <abbrev>BSD</abbrev> et c'est pourquoi nous nous proposons, dans ce support, de les présenter principalement dans un contexte d'interactivité où ils sont plutôt efficaces. 
</para>

<para>Voici néanmoins un résumé des différentes familles de Shells : 
<itemizedlist>
	<listitem><para>sh ("Bourne shell", Steve Bourne) : shell historique (disponible sur tous les Unix)</para></listitem>
    <listitem><para>csh ("C-shell", Bill Joy) : shell BSD (disponible sur tous les Unix) </para></listitem>
    <listitem><para>ksh ("Korn shell") : shell normalisé POSIX (P1003.2) et ISO (HP, Solaris)</para></listitem>
    <listitem><para>bash ("Bourne again shell" de Brian Fox et Chet Ramey) : Ksh du domaine public (installé sur toutes les machines Linux) </para></listitem>
    <listitem><para>zsh ("Zero shell") : Ksh du domaine public (installé sur toutes les machines) </para></listitem>
    <listitem><para>tcsh ("Toronto C-shell")</para></listitem>
    <listitem><para>rc (Plan9, Tom Duff)</para></listitem>

</itemizedlist>

</para>

  </abstract>

  <sect1>
    <title>Principes de fonctionnement de <command>&fshell;</command></title>    
    <sect2>      
      <title>Rôle d'un &shell; </title>
      <para>
Le &shell; est un interpréteur de commande en ligne. Chaque entrée sur un terminal est analysée et décomposée en terme d'instructions à exécuter. Ces instructions peuvent impliquer des commandes internes que le &shell; connaît et est en mesure d'exécuter directement, ou bien d'autres commandes déclenchant des programmes que le &shell; va tenter de localiser et de lancer. Le &shell; dispose d'instructions (structures de contrôle, ...) et de variables qui le rende en partie comparable à un langage de programmation, de sorte que l'on peut écrire des <foreignphrase>shell scripts</foreignphrase>, littérallement de petits ou moyens programmes rédigé en &shell;. 
      </para>

      <para>Un interpréteur &shell; exécutent trois types de commandes : </para>

      <orderedlist numeration="lowerroman" spacing="normal">
	<listitem><para>Les <emphasis>commandes internes</emphasis> [<foreignphrase>built-in commands</foreignphrase>], comme par exemple : <command>cd</command>, <command>pwd</command>, <command>umask</command> ... ou bien encore les éléments algorithmiques tels <command>if .. then .. else .. endif</command>, <command>foreach ...</command> ...</para></listitem>
	<listitem><para>Les <emphasis>commandes externes</emphasis> indépendantes du &shell; et localisées dans les répertoires, comme par exemple : <command>ls</command> (<filename>/bin/ls</filename>), <command>find</command> (<filename>/usr/bin/find</filename>) ... Ces commandes nécessitent la création d'un nouveau &shell; pour leur exécution contrairement à celles relevant de la première catégorie.</para></listitem>
	<listitem><para>Les commandes définies par un <command>alias</command>.</para></listitem>
      </orderedlist>
    </sect2>
    <sect2>
      <title>Algorithme de fonctionnement du <command>&shell;</command></title>
      <para>Le &shell; est le premier processus d'une session, son choix est indiqué dans le fichier <filename>/etc/passwd</filename>. IL est attaché au terminal console (login), ou à un pseudo-terminal (remote login, activation d'une fenêtre).</para>
<para>Le &shell; ouvre initialement trois fichiers standards : 
	  <itemizedlist>
	  <listitem><para>l'entrée standard (<filename>stdin</filename>, fd=0), par défaut le clavier</para></listitem>
	  <listitem><para>la sortie standard (<filename>stdout</filename>, fd=1), par défaut l'écran</para></listitem>
	  <listitem><para>lasortie erreur standard (<filename>stderr</filename>, fd=2), par défaut l'écran</para></listitem>
	</itemizedlist>
</para>

<para>Le &shell; lit sur son entrée standard <itemizedlist>
	  <listitem><para> la commande jusqu'à la fin de ligne (<computeroutput>\n</computeroutput>) et interprète les métacaractères et les opérateurs</para></listitem>
          <listitem><para>les lignes de commandes jusqu'à la fin de fichier (<computeroutput>^D</computeroutput>) dans le cas d'un script</para></listitem>
	</itemizedlist>
</para>
<para>Au lancement d'une commande, le &shell; <itemizedlist>
          <listitem><para>recherche  l'éxécutable de la commande à l'aide du <varname>PATH</varname> dans le cas d'une commande externe</para></listitem>
          <listitem><para>exécute en premier plan dans un processus fils la commande et en attend le résultat  </para></listitem>
          <listitem><para>exécute en arrière plan dans un processus fils la commande, sans en attendre le résultat (non bloquant)</para></listitem>
	</itemizedlist>
</para>


    </sect2>
    <sect2>
      <title>Caractéristiques de <command>&fshell;</command></title>
      <para>
	  <itemizedlist>
	  <listitem><para>il possède un mécanisme d'historisation et de rappel (et d'éditions des commandes &fshell2;) ; </para></listitem>
	  <listitem><para>il permet le contrôle des processus (suspension), reprise asynchrone (<foreignphrase>background</foreignphrase>) ou interactive (<foreignphrase>foreground</foreignphrase>)) ; </para></listitem>
	  <listitem><para>il permet de traiter les tableaux de caractères ;</para></listitem>
	  <listitem><para>il possède des directives de programmation proche du C ;</para></listitem>
	  <listitem><para>il possède un mécanisme de <foreignphrase>completion</foreignphrase> ; </para></listitem>
	  <listitem><para>il permet le calcul arithmétique.</para></listitem>
	</itemizedlist>
</para>
    </sect2>
    
    <sect2>
      <title>Fichiers de configuration de <command>&fshell;</command></title>
    <para>Lors du <foreignphrase>login</foreignphrase>, <command>&fshell;</command> exécute les instructions contenues dans le  fichier <filename>/etc/csh.cshrc</filename> puis celles du fichier <filename>/etc/csh.login</filename> puis celles de <filename>~/.cshrc</filename> (<command>tcsh</command> lit le script <filename>~/.tcshrc</filename>, s'il existe et sinon <filename>~/.cshrc</filename>) et enfin celles de <filename>~/.login</filename>. La signification du caractère <command>~</command> est donnée en <xref linkend="metacar"/>. Lors de la fin de session (<foreignphrase>logout</foreignphrase>) <command>&fshell;</command> ou <command>tcsh</command> exécutent les commandes des fichiers <filename>/etc/csh.logout</filename> et  <filename>~/.logout</filename>, dans cet ordre.</para>

      <para>Un sous-&shell;, ne lit pas les fichiers suffixés en <filename>.login</filename> à son démarrage ni les fichiers suffixés en <filename>.logout</filename> à sa terminaison. Il lit par contre les fichiers<filename>~/.cshrc</filename> ou <filename>~/.tcshrc</filename>. Un sous-shell est un shell lancé depuis un autre shell, en appelant directement son exécutable.</para>

      <para>De ce qui précède, on déduit que les commandes à exécuter une seule fois pendant une session sont à placer dans les fichiers suffixés en <filename>.login</filename> (typiquement les variables d'environnement), tandis que les autres sont à placer dans les fichiers suffixés en  <filename>.cshrc</filename>. </para>



      <para>Le fichier <filename> ~/.cshrc</filename> contient typiquement :
<itemizedlist>
	  <listitem><para>la définition des alias ; </para></listitem>
	  <listitem><para>la définition des paramètres de fonctionnement ;</para></listitem>
	  <listitem><para>l'initialisation des variables.</para></listitem>
	</itemizedlist>
</para>

      <para>
<example>
	  <title>fichier <filename> ~/.cshrc</filename> </title>
<programlisting width="80">
<![CDATA[
# ~/.cshrc
#
# $FreeBSD: src/share/skel/dot.cshrc,v 1.10.2.3 2001/08/01 17:15:46 obrien Exp $#
# .cshrc - csh resource script, read at beginning of execution by each shell
# see also csh(1), environ(7).
#

# Les alias
# -------------------------
alias j         jobs -l
alias la        /bin/ls -aoBG
alias lf        /bin/ls -FABG
alias ll        /bin/ls -loABG
alias gv        /usr/X11R6/bin/gv -color -safer -quiet \ 
-media a4 -portrait
alias rm        /bin/rm -i
alias wget      `which wget` -N -c -S
alias emacs     `which emacs` -q
alias gnuplot   `which gnuplot` -background ivory
alias xdvi      `which xdvi` -fg DarkSlateGray  -paper a4 
alias xfig      `which xfig` -center -centim -pap a4 -po
alias dvips     `which dvips` -t a4 -o out.ps
alias h         'history -r \!* | less'
alias psnup     `which psnup` -pa4 -2up -m0.5cm

# Paramètres et variables.
# -------------------------
limit coredumpsize 0  # prevent core files from being written to disc
# A righteous umask
umask 077
set prompt='%B%n%b@%m:%c > '
set prompt2='%B%n%b:>> '
set path = (/usr/local/sbin /usr/local/bin /sbin /bin /usr/sbin \
/usr/bin /usr/X11R6/bin $HOME/bin)
set correct = cmd

/usr/X11R6/bin/xrdb -load ~/.Xdefaults >& /dev/null

if ($?prompt) then
        # An interactive shell -- set some stuff up
        set filec
        set history = 2048
        set savehist = 2048
        set histfile = ~/.history
        set mail = (/var/mail/$USER)
        set notify      
        set addsuffix
        set autolist
        set machbeep = nomatch
        set cdpath = ( ~ ~/bin )
        set symlinks = ignore
        if ( $?tcsh ) then
                set echo_style = both
                set histdup = all
                set savehist = ( 2000 merge )
                bindkey "^W" backward-delete-word
                bindkey -k up history-search-backward
                bindkey -k down history-search-forward
                source ~/.tcsh_comp
        endif
endif
]]>
</programlisting>
	</example>
</para>


<para> Le fichier <filename> ~/.login </filename> contient essentiellement la définition des variables d'environnement.</para>

<para>
<example>
	  <title> fichier <filename> ~/.login</filename> </title>
<programlisting width="80">
<![CDATA[
# ~/.login                                                                      

setenv LC_CTYPE fr_FR.ISO8859-15
setenv PAGER less
setenv MOZILLA_HOME /usr/X11R6/bin/mozilla
setenv MACHTYPE i386
setenv EDITOR emacs
setenv HOSTTYPE FreeBSD
setenv CPUTYPE k7
setenv OSTYPE FreeBSD
setenv TEXEDIT emacs
setenv VENDOR amd
setenv SHLVL 1
setenv LSCOLORS "ExFxbxcxBxdxHBhbafacad" 
setenv CLICOLOR 1
setenv CLICOLOR_FORCE 1

# COLORTERM to "rxvt"
setenv COLORTERM "rxvt"

# COLORFGBG to "default" 
setenv COLORFGBG "default" 

setenv RSYNC_RSH /usr/bin/ssh
setenv CVSROOT /home/cvsroot
setenv BLOCKSIZE       K
setenv TERM xterm-color

[ -x /usr/games/fortune ] && /usr/games/fortune freebsd-tips
]]>
</programlisting>
	</example>
</para>
      



 <para> Le fichier <filename> ~/.logout </filename> contient essentiellement des commandes de suppression de fichiers inutiles.</para>
     
      <para>
<example>
	  <title> fichier <filename> ~/.logout</filename> </title>
<programlisting width="80">
<![CDATA[
# ~/.logout                                                                     

echo -n "clean up before logout ..."
find $HOME \( -type f \
              \( -name a.out -o -name "*.bak" -o -name core  -o \
                 -name "#*#" -o -name "#.*#"  -o -name "*.o" -o \
                 -name "*~"  -o -name ".*~" \) -exec /bin/rm -f {} \; > /dev/null \)
echo "... done" 
echo "last connexion at [`date +%Y-%M-%d` a `date +%H:%I:%S`] pour [`logname`] s
ur [`tty`]" > ~/.deconnex
]]>
</programlisting>
	</example>
    </para>
      <qandaset defaultlabel='qanda'>
	<qandaentry>
	  <question>
	    <para>
            Quel est le rôle de la commande <command>find</command> dans le contexte du listing précédent (<filename>~/.logout</filename>) ?
            </para>
	  </question>
	  <answer>
	    <para/>
	  </answer>
	</qandaentry>
      </qandaset>


      <para>Il est possible à tout moment et notamment après une modification de réexécuter les fichiers au moyen de la commande <command>source</command>.
<programlisting width="80">
$ > source ~/.login                                                             
$ > source ~/.cshrc
</programlisting>


<warning>
	  <para>Dans les distributions <emphasis>xBSD</emphasis> on peut voir les deux fichiers suivants : <filename>/.login</filename> et <filename>/.profile</filename> (situés à la racine). Ils sont exécutés uniquement dans le mode mono-utilisateur [<foreignphrase>single-user mode</foreignphrase>]. Leurs modifications sont à faire avec le plus grand soin.</para>
	</warning>

</para>

  </sect2>


    <sect2 id="envvar">
      <title>Variables prédéfinies et d'environnement</title>
      <para>On parle de <emphasis>variables d'environnement</emphasis> car elles sont <quote>automatiquement</quote> transmises à tous les processus fils du &shell;, &ie; tous les processus lancés par ce &shell;.</para> 

      <para>Les variables qui suivent ont un sens particulier pour le &shell; (&fshell; et &fshell2;), elles sont utilisées par certaines commandes du &shell; ou du système. Parmi elles, <varname>argv</varname>, <varname>cwd</varname>, <varname>home</varname>, <varname>path</varname>, <varname>prompt</varname>, <varname>shell</varname> et <varname>status</varname> sont toujours définies par le &shell;. Si l'on exclut les variables <varname>cwd</varname> et <varname>status</varname>, leur positionnement intervient seulement à l'initialisation. Ces variables ne sont plus modifiées, sauf éventuellement par l'utilisateur.
</para> 

      <para>
          <table> <!-- orient='land' pgwide='0'> -->
	  <title> Variables d'environnement </title>
	  <!-- one of (graphic mediaobject tgroup) -->
	  <tgroup cols="2" align='left'>

	    <thead valign='middle'>
	      <row>
		<!-- one of (entrytbl entry) -->
		<entry align='center'> Variable d'environnement </entry>
		<entry align='center'> Sémantique </entry>
	      </row>
	    </thead>
	    <tbody valign='middle'>
	      <row>
		<!-- one of (entrytbl entry) -->
		<entry align='left'><varname>argv</varname></entry>
		<entry>Arguments du &shell;, résultant de la substitution des paramètres positionnels.
                  <varname>$argv[1]</varname> correspond  à <varname>$1</varname>, <varname>$argv[2]</varname> à <varname>$2</varname> ...</entry>
	      </row>

	       <row>
		<entry align='left'><varname>autologout</varname></entry>
		<entry>[<emphasis role="bold">&fshell2;</emphasis>] Positionné à un certain nombre de minutes, permet de déconnecter automatiquement l'utilisateur au bout de cette période d'inactivité.</entry>
	      </row>


	      <row>
		<!-- one of (entrytbl entry) -->
		<entry align='left'><varname>cdpath</varname></entry>
		<entry> Liste de répertoires alternatifs dans lesquels sera effectuée la recherche
des sous-répertoires lors de l'utilisation de la commande <command>cd</command> avec un argument de type nom relatif.</entry>
	      </row>

	       <row>
		<entry align='left'><varname>correct</varname></entry>
		<entry>[<emphasis role="bold">&fshell2;</emphasis>] Positionnable à <emphasis>all</emphasis> ou <emphasis>cmd</emphasis>. Dans le deuxième cas, permet la correction des erreurs de typos sur les noms de commandes.</entry>
	      </row>

	      
	      
	      <row>
		<!-- one of (entrytbl entry) -->
		<entry align='left'><varname>cwd</varname></entry>
		<entry>Chemin absolu du répertoire courant.</entry>
	      </row>

	      <row>
		<!-- one of (entrytbl entry) -->
		<entry align='left'><varname>echo</varname></entry>
		<entry></entry>
	      </row>


	      <row>
		<!-- one of (entrytbl entry) -->
		<entry align='left'> <varname>filec</varname> </entry>
		<entry> Permet la <foreignphrase>completion</foreignphrase> des noms de fichiers. </entry>
	      </row>


	      <row>
		<!-- one of (entrytbl entry) -->
		<entry align='left'> <varname>histchars</varname></entry>
		<entry> Chaîne de caractères à utiliser dans les substitutions de l'historique. Les éléments de cette chaîne remplacent les caractères standards, ainsi le premier caractère de cette chaîne remplace le '<command>!</command>', le second remplace le '<command>^</command>' ...</entry>
	      </row>


	      <row>
		<!-- one of (entrytbl entry) -->
		<entry align='left'><varname>histfile</varname></entry>
		<entry> Chemin d'accès au fichier d'historique. </entry>
	      </row>


	      <row>
		<!-- one of (entrytbl entry) -->
		<entry align='left'><varname>history</varname></entry>
		<entry> Permet de contrôler le nombre de lignes de l'historique. Noter que la dernière commande exécutée est toujours sauvegardée dans l'historique.</entry>
	      </row>


	      <row>
		<!-- one of (entrytbl entry) -->
		<entry align='left'><varname>home</varname></entry>
		<entry>Désigne le répertoire de localisation de celui qui invoque la commande. L'expansion de nom de fichier <command>~</command> se réfère à cette variable.</entry>
	      </row>


	      <row>
		<!-- one of (entrytbl entry) -->
		<entry align='left'><varname>ignoreeof</varname></entry>
		<entry>Le positionnement de cette variable permet au &shell;  d'ignorer le caractère de fin de fichier quand il est généré depuis un terminal. Cela permet donc d'immuniser le &shell; d'une fin accidentelle déclenchée par la séquence <command>^D</command> (lire <command>&lt;CTRL&gt;-D</command>).</entry>
	      </row>

	      
<row>
		<!-- one of (entrytbl entry) -->
		<entry align='left'><varname>inputmode</varname></entry>
		<entry>[<emphasis role="bold">&fshell2;</emphasis>] Définit le mode en insertion (par défaut) ou en <foreignphrase>overwrite</foreignphrase> pour l'édition de la ligne de commande .</entry>
	      </row>

	      <row>
		<!-- one of (entrytbl entry) -->
		<entry align='left'><varname>mail</varname></entry>
		<entry> Indique le fichier dans lequel le &shell;  contrôle l'arrivée de nouveaux messages.
                    Si la première valeur spécifiée dans <varname>mail</varname> est numérique, elle surcharge l'intervalle de temps entre chaque
                vérification, fixé par défaut à 10 minutes.
                Si la variable spécifie différents fichiers, chacun d'eux sera scruté pour détecter
                l'arrivée de nouveaux messages.
		</entry>		      
	      </row>
	      
	      <row>
		<!-- one of (entrytbl entry) -->
		<entry align='left'> <varname>noclobber</varname> </entry>
		<entry> Modifie la sémantique des commandes de redirections <command>&gt;</command> et <command>&gt;&gt;</command> permettant ainsi d'éviter un effacement accidentel. L'utilisation de <command>&gt;</command> renvoit une erreur si le fichier existe.
Quand à <command>&gt;&gt;</command>, elle se réfère uniquement aux fichiers existants.
</entry>
	      </row>


	      <row>
		<!-- one of (entrytbl entry) -->
		<entry align='left'> <varname>noglob</varname> </entry>
		<entry> Si cette variable est positionnée, elle inhibe la fonctionnalité d'expansion des noms de fichiers. Surtout utile dans les scripts &shell;.</entry>
	      </row>

	      <row>
		<!-- one of (entrytbl entry) -->
		<entry align='left'> <varname>nonomatch</varname> </entry>
		<entry> Si cette variable est positionnée, il n'y a pas d'erreurs lorsque le mécanisme d'expansion des noms de fichiers ne correspond pas à tous les fichiers existants. Dans ce cas le motif est retourné.</entry>
	      </row>

	      <row>
		<!-- one of (entrytbl entry) -->
		<entry align='left'><varname>notify</varname></entry>
		<entry> Si positionné alors permet au &shell;  de notifier de manière asynchrone la <foreignphrase>completion</foreignphrase> des <foreignphrase>jobs</foreignphrase>. Le comportement par défaut spécifie de présenter la <foreignphrase>completion</foreignphrase> des <foreignphrase>jobs</foreignphrase> avant d'imprimer le <foreignphrase>prompt</foreignphrase>.</entry>
	      </row>

	      <row>
		<!-- one of (entrytbl entry) -->
		<entry align='left'> <varname>path</varname> </entry>
		<entry>Définit l'ensemble des chemins dans lesquels le &shell;  recherche les commandes externes à exécuter.</entry>
	      </row>
 
	      <row>
		<!-- one of (entrytbl entry) -->
		<entry align='left'><varname>prompt</varname></entry>
		<entry> Définit l'invite de commandes en mode interactif. </entry>
	      </row>

	       <row>
		<!-- one of (entrytbl entry) -->
		<entry align='left'><varname>rmstar</varname></entry>
		<entry>[<emphasis role="bold">&fshell2;</emphasis>] Si positionné, permet de demander à l'utilisateur confirmation lorsqu'il tape la commande <computeroutput>rm *</computeroutput>.</entry>
	      </row>


	      <row>
		<!-- one of (entrytbl entry) -->
		<entry align='left'><varname>savehist</varname></entry>
		<entry> Si l'argument est numérique, spécifie le nombre de lignes sauvegardées dans <filename>~/.history</filename>,
quand l'utilisateur se déloggue.</entry>
	      </row>


	      <row>
		<!-- one of (entrytbl entry) -->
		<entry align='left'><varname>shell</varname></entry>
		<entry> Fichier dans lequel réside le &shell;.</entry>
	      </row>

	      <row>
		<entry align='left'><varname>shlvl</varname></entry>
		<entry>[<emphasis role="bold">&fshell2;</emphasis>] Nombre de &shell; empilés, remis à 1 par un &shell; de <foreignphrase>login</foreignphrase>.</entry>
	      </row>

	      <row>
		<!-- one of (entrytbl entry) -->
		<entry align='left'><varname>status</varname></entry>
		<entry>Statut retourné par la dernière commande exécutée.</entry>
	      </row>

	      <row>
		<!-- one of (entrytbl entry) -->
		<entry align='left'><varname>time</varname></entry>
		<entry>Si cette variable est positionnée (valeur en secondes), alors toute commande dont la durée d'exécution dépasse cette valeur est suivie à sa terminaison de l'affichage de statistiques sur les temps utilisateur, système et réel consommés ainsi que le ratio temps utilisateur et temps système sur temps réel consommé. 
</entry>
	      </row>

	      <row>
		<!-- one of (entrytbl entry) -->
		<entry align='left' ><varname>verbose</varname></entry>
		<entry></entry>
	      </row>

	    </tbody>
	  </tgroup>
	</table>
</para>

      <formalpara>
      <title>Relations entre variables du &shell; et les variables d'environnement</title>
      <para>En &fshell; comme en &fshell2; certaines variables du &shell; et des variables d'environnement sont maintenues à des valeurs identiques par le &shell;. Ce sont les variables <varname>user</varname> et <varname>USER</varname>, <varname>group</varname> et <varname>GROUP</varname>,  <varname>home</varname> et <varname>HOME</varname>, <varname>term</varname> et <varname>TERM</varname>, <varname>path</varname> et <varname>PATH</varname>, et enfin <varname>shlvl</varname> et <varname>SHLVL</varname>.
</para>
      </formalpara>

    </sect2>

    <sect2 id="metacar">
      <title>Métacaractères et autres caractères spéciaux du &shell;</title>
      <para>Les métacaractères jouent le rôle de classe de représentation des fichiers dans le contexte du répertoire courant si rien n'est précisé ou bien dans celui du répertoire explicitement nommé.</para>
      <itemizedlist>
	<listitem>     
	  <para> Le caractère <command>~</command> placé en première position désigne le répertoire personnel de l'utilisateur courant : </para>
	  <informalexample>
<para>
<programlisting width="80">
<![CDATA[
$ echo ~                                                                        
/home/ikare

$ls -l data/
total 8
drwxrwx---  17 ikare  ikare  2048 19 fév 17:25 docs
drwxrwx---   9 ikare  ikare   512  5 nov 16:32 images
drwxrwx---   7 ikare  ikare   512 18 avr 12:38 travail
drwxrwxr-x   4 ikare  ikare   512  5 nov 13:46 web
]]>
</programlisting>
</para>
	   </informalexample>
	</listitem>

	<listitem>     
	  <para> Le caractère <command>*</command> est substituable par n'importe quelle combinaison de 0 ou plusieurs caractères.</para>
	  <para> Exemple : Lister l'ensemble des fichiers possédant le suffixe <filename>.sh</filename> du répertoire courant : </para>
	  <para>
<programlisting width="80">
<![CDATA[
$ ls *.sh
cmd.sh          fcomp.sh        fdate.sh        ftestparm.sh    ftestvect.sh

]]>
</programlisting>
          </para>

	  <informalexample>
	  <para> Exemple : Lister les fichiers (non <quote>cachés</quote>) du répertoires courant :</para>
<para>
<programlisting width="80">
$echo *
cmd.sh fcomp.sh fcomp.sh.2 fdate.sh ftestparm.sh ftestvect.sh ftestvect.sh.2 shells.pdf shells.xml
</programlisting>
</para>
	  </informalexample>

      <warning><para> Les fichiers commençant par le caractère <command>.</command> ou fichiers <quote>cachés</quote> d'&unix; [<foreignphrase>dot files</foreignphrase>] ne peuvent être remplacés par aucun caractère, &ie; le caractère <quote><command>*</command></quote> est inopérant.</para></warning>
	
	</listitem>

	<listitem> 
	  <para> Le caractère <command>?</command> est substituable par un unique caractère quelconque.</para>
	  <informalexample>
	  <para> Exemple : Lister les fichiers commençant par le motif <filename>ft</filename> et dont le suffixe est de trois caractères :</para>

<programlisting width="80">
<![CDATA[
$ ls ft*.??
ftestparm.sh    ftestvect.sh
]]>                                            
</programlisting>

	</informalexample>
	</listitem>

	<listitem> 
	  <para> Les caractères <command>[]</command> permettent une substitution par un caractère parmi l'ensemble dénoté par les crochets.</para>
	  <informalexample>
	    <para> Exemple : Lister les fichiers <quote>cachés</quote> du répertoire <filename>$HOME</filename> de l'utilisateur courant, dont le second caractère est compris entre 'a' et 'e' (le premier étant le <quote>.</quote>) :</para>	
<programlisting width="80">
<![CDATA[
$ ls -d ~/.[a-e]*
/home/ikare/.beryl                      /home/ikare/.dbus
/home/ikare/.beryl-managerrc            /home/ikare/.deconnex
/home/ikare/.beryl-managerrc.7RFBPT     /home/ikare/.dia
/home/ikare/.cache                      /home/ikare/.dmrc
/home/ikare/.config                     /home/ikare/.e
/home/ikare/.cshrc                      /home/ikare/.emerald
/home/ikare/.danpei                     /home/ikare/.evolution
/home/ikare/.dasher

]]>
</programlisting>
	  </informalexample>

	  <informalexample>
	    <para> Autre exemple, utilisation de la négation (extension <command>tcsh</command>) marqué par le caractère <command>^</command> : Lister les fichiers cachés du répertoire <filename>$HOME</filename> de l'utilisateur courant, dont le second caractère n'est ni '.',  ni 'a', ni 'b', ni 'c', ni 'd' ni 'e' (le premier étant un '.') : </para>
<programlisting width="80">
<![CDATA[
$ ls -d ~/.[^.a-e]*                                                             
/home/ikare/.3ddesktop                  /home/ikare/.mail_aliases
/home/ikare/.FVWM95-errors              /home/ikare/.mailrc
/home/ikare/.ICEauthority               /home/ikare/.mcop
/home/ikare/.Trash                      /home/ikare/.mcoprc
/home/ikare/.Xauthority                 /home/ikare/.metacity
/home/ikare/.fluxbox                    /home/ikare/.mozilla
/home/ikare/.fontconfig                 /home/ikare/.mplayer
/home/ikare/.fonts.cache-1              /home/ikare/.nautilus
/home/ikare/.fvwm                       /home/ikare/.nvu
/home/ikare/.gconf                      /home/ikare/.openoffice.org2
/home/ikare/.gconfd                     /home/ikare/.profile
/home/ikare/.gftp                       /home/ikare/.prx4iXfy8
/home/ikare/.gimp-2.3                   /home/ikare/.qt
/home/ikare/.gkrellm2                   /home/ikare/.recently-used
/home/ikare/.gnome                      /home/ikare/.recently-used.xbel
/home/ikare/.gnome2                     /home/ikare/.rhosts
/home/ikare/.gnome2_private             /home/ikare/.saves-1567-ix.fremens
/home/ikare/.gqview                     /home/ikare/.saves-1848-ix.fremens
/home/ikare/.gstreamer-0.10             /home/ikare/.shrc
/home/ikare/.gtkrc                      /home/ikare/.ssh
/home/ikare/.gtkrc-1.2-gnome2           /home/ikare/.themes
/home/ikare/.gtksee                     /home/ikare/.thumbnails
/home/ikare/.history                    /home/ikare/.thunderbird
/home/ikare/.icons                      /home/ikare/.vlc
/home/ikare/.java                       /home/ikare/.wm_style
/home/ikare/.kde                        /home/ikare/.wmndrc
/home/ikare/.keylaunchrc                /home/ikare/.xdvirc
/home/ikare/.lesshst                    /home/ikare/.xemacs
/home/ikare/.local                      /home/ikare/.xfce
/home/ikare/.login                      /home/ikare/.xmms
/home/ikare/.login_conf                 /home/ikare/.xscreensaver
/home/ikare/.logout                     /home/ikare/.xsession-errors
/home/ikare/.macromedia                 /home/ikare/.xwm.msgs

]]>
</programlisting>
	  </informalexample>

	</listitem>

	<listitem>
	  <para>Les caractères <command>{ }</command> permettent la substitution par un mot de l'énumération dénotée par les accolades.</para>

<informalexample>
	  <para> Exemple : Lister les fichiers se terminant par les suffixes .xml et .pdf et .fo :</para>

<programlisting width="80">
<![CDATA[
$ ls *.{xml,pdf}
shells.pdf      shells.xml                            
]]>
</programlisting>

	</informalexample>
	</listitem>

	<listitem><para>Quelques autres caractères spéciaux </para>
	  <table frame="all" orient="port">
	    <title>Autres caractères spéciaux du &shell;</title>
	    <!-- one of (graphic mediaobject tgroup) -->
	    <tgroup cols="2" align='left'>


	      <thead>
		<row>
		  <!-- one of (entrytbl entry) -->
		  <entry align='center'> Caractère </entry>
		  <entry align='center'> Sémantique </entry>
		</row>
	      </thead>
	      
	      <tbody>
		<row>
		  <!-- one of (entrytbl entry) -->
		  <entry align='center'><command>;</command></entry>
		  <entry>Séparateur de commande, &ie; opérateur de séquentialité.</entry>
		</row>
		
		<row>
		  <!-- one of (entrytbl entry) -->
		  <entry align='center'><command>&amp;</command></entry>
		  <entry>Séparateur de commande qui place la commande qui le précède en arrière-plan, &ie; en exécution asynchrone.</entry>
		</row>

		<row>
		  <!-- one of (entrytbl entry) -->
		  <entry align='center'><command>\</command></entry>
		  <entry>Quote le caractère qui le suit et notamment pour les caractères spéciaux, inhibe leur sémantique particulière.</entry>
		</row>
		
		<row>
		  <!-- one of (entrytbl entry) -->
		  <entry align='center'><command>$</command></entry>
		  <entry>Accède au contenu de la variable.</entry>
		</row>

		<row>
		  <!-- one of (entrytbl entry) -->
		  <entry align='center'><command>'</command></entry>
		  <entry>[<foreignphrase>quote</foreignphrase>] Quote le texte qui le suit jusqu'au <command>'</command> fermant.</entry>
		</row>

		<row>
		  <!-- one of (entrytbl entry) -->
		  <entry align='center'><command>`</command></entry>
		  <entry>[<foreignphrase>backquote</foreignphrase>] Considère le texte quoté comme une commande et la remplace par le résultat de son évaluation.</entry>
		</row>

		<row>
		  <!-- one of (entrytbl entry) -->
		  <entry align='center'><command>"</command></entry>
		  <entry>[<foreignphrase>double quote</foreignphrase>] Quote le texte qui le suit en interpolant les éventuelles variables qu'il contient.</entry>
		</row>

		<row>
		  <!-- one of (entrytbl entry) -->
		  <entry align='center'><command>!</command></entry>
		  <entry>Substitution dans l'historique.</entry>
		</row>

		<row>
		  <!-- one of (entrytbl entry) -->
		  <entry align='center'><command>|</command></entry>
		  <entry>Tube [<foreignphrase>pipe</foreignphrase>].</entry>
		</row>

		<row>
		  <!-- one of (entrytbl entry) -->
		  <entry align='center'><command>&gt;</command> et <command>&gt;&gt;</command></entry>
		  <entry>Redirection de la sortie standard.</entry>
		</row>

		<row>
		  <!-- one of (entrytbl entry) -->
		  <entry align='center'><command>&lt;</command> et <command>&lt;&lt;</command></entry>
		  <entry>Redirection de l'entrée standard.</entry>
		</row>

		<row>
		  <!-- one of (entrytbl entry) -->
		  <entry align='center'><command>#</command></entry>
		  <entry>Marque le début d'un commentaire, &ie; pas d'expansion.</entry>
		</row>

		<row>
		  <!-- one of (entrytbl entry) -->
		  <entry align='center'><command>&amp;&amp;</command></entry>
		  <entry>Et [<foreignphrase>And</foreignphrase>] logique.</entry>
		</row>

		<row>
		  <!-- one of (entrytbl entry) -->
		  <entry align='center'><command>||</command></entry>
		  <entry>Ou [<foreignphrase>Or</foreignphrase>] logique.</entry>
		</row>


	      </tbody>

	    </tgroup>
	  </table>
</listitem>

      </itemizedlist>
    </sect2>
</sect1>






<!-- 2e PARTIE -->
  <sect1>
    <title>Les commandes internes</title>    

    <sect2>
      <title><command>source</command> </title>
      <para>Cette commande exécute le fichier (et ces éventuels arguments) qui lui est passé en argument dans le &shell; courant (&ie; pas de <command>fork</command> et donc modification (éventuelle) du &shell; courant).
</para>
      <para>
<programlisting width="80">
<![CDATA[
$ source ~/.login                                                               
]]>
</programlisting>
</para>
    </sect2>
    <sect2 id="setenv">
      <title><command>setenv/unsetenv</command></title>
      <para> La commande <command>setenv</command> permet d'initialiser une variable d'environnement, &ie; une variable qui sera transmise à tous les processus fils du &shell;.</para>

       <para>
<programlisting width="80">
<![CDATA[
setenv OSTYPE  FreeBSD                                                          
setenv CPUTYPE k7
setenv PAGER   less
]]>
</programlisting>
    </para>

      <para> La commande <command>unsetenv</command> permet de supprimer une variable d'environnement.</para>
    </sect2>


    <sect2>      
      <title> <command>set/unset</command></title>
      <para> La commande <command>set</command> a deux fonctions :</para>
      <itemizedlist>
	<listitem><para> l'initialisation d'une variable :</para></listitem>
      </itemizedlist>
      <para>
<programlisting width="80">
<![CDATA[
$ set path=( $path ~/bin )                                                      
]]>
</programlisting>     
Cette déclaration permet d'enrichir la variable <command>path</command> du répertoire <command>bin</command> de l'utilisateur.
</para>    

      <itemizedlist>
	<listitem><para> la déclaration d'une option : </para></listitem>
      </itemizedlist>
      <para>
<programlisting width="80" format="linespecific">
<![CDATA[
$ set ignoreeof                                                                 
]]>
</programlisting>
Cette option permet d'immuniser <command>&fshell;</command> d'une destruction accidentelle. Il est normalement possible de clôre un terminal avec la séquence <command>^D</command> (lire <command>&lt;CTRL&gt;-D</command>), mais si on positionne  l'option <command>ignoreeof</command> la séquence précédente n'a plus d'effet.</para>

      <para> La commande <command>unset</command> a évidement un effet symétrique. Elle permet donc de désarmer une option ou de supprimer une variable. </para>

      <important><para> La portée de ces actions est limitée au &shell; courant contrairement à la commande précédente (&cf; <xref linkend="setenv"/>).</para></important>

</sect2>


    <sect2>      
      <title> <command>alias</command>/<command>unalias</command></title>
      <para> Ce mécanisme permet de définir ou de redéfinir une commande. Exemple : </para>
      
      <para>
<programlisting width="80">
<![CDATA[
$ alias la /bin/ls -aoBG          # definition de l'alias la                    
$ alias rm /bin/rm -i             # definition de l'alias rm
$ alias                           # afficher les alias courants
la      (/bin/ls -aoBG)
rm      (/bin/rm -i)
]]>
</programlisting>
      </para>   
      
      <para> En général, on place ces <command>alias</command> dans le fichier <filename>~/.cshrc</filename>. Si on veut supprimer un <command>alias</command> on utilise la commande <command>unalias</command> comme suit :</para>
      
      <para>
<programlisting width="80">
<![CDATA[
$ unalias rm                                                                    
$ alias                                # afficher les alias courants
la      (/bin/ls -aoBG)
]]>
</programlisting>
      </para>
      
      <para>Pour ré-accéder à la commande masquée par son alias, comme dans l'exemple précédent où nous avons surchargé la commande classique <command>rm</command>, il suffit de : 
      <itemizedlist>
	  <listitem><para>Soit utiliser la commande par son nom absolu : <command>/bin/rm</command>.</para></listitem>
	  <listitem><para>Soit faire précéder la commande du caractère <foreignphrase>backslash</foreignphrase> (\), on tape donc toujours dans le cadre de l'exemple précédent : <command>\rm</command></para></listitem>
	</itemizedlist>
        </para>
        
      <qandaset defaultlabel='qanda'>
	<qandaentry>
	  <question>
	    <para>
            Que signifie la commande <command>rm -i</command> ?
            </para>
	  </question>
	  <answer>
	    <para/>
	  </answer>
	</qandaentry>
      </qandaset>
    </sect2>

    <sect2>
      <title><command>umask</command></title>
      <para>Cette commande permet de spécifier (si elle est suivie d'un argument valide) ou d'afficher la valeur du masque de création des objets &ie; des fichiers.</para>
 <para>
<programlisting width="80">
<![CDATA[
$ umask  # affiche la valeur telle que prédéfinie dans ~/.cshrc                 
77       # autrement dir 0077   
$ umask 0027
$ umask
27       # autrement dit 0027
]]>
</programlisting>
</para>
    </sect2>
    
    <sect2>      
      <title> Historique </title>      
      <para>Ce mécanisme a pour rôle de mémoriser les <varname>n</varname> dernières commandes entrées, ce nombre étant un paramètre réglable. Cela permet de visualiser, d'éditer et/ou exécuter à nouveau les commandes mémorisées. La commande suivante permet d'activer l'historisation des commandes, elle signifie que les 512 dernières commandes seront mémorisées : 

<programlisting width="80">
<![CDATA[
$ set history = 512                                                             
]]>
</programlisting>
</para>

<para>La commande suivante permet en plus de sauvegarder les <varname>m</varname> dernières commandes dans <filename>~/.history</filename> au <command>logout</command>. Il est évident que <varname>m</varname> est au plus égale à <varname>n</varname>. Ici, nous ne retenons que les 256 dernières commandes : 

<programlisting width="80">
<![CDATA[
$ set savehist = 256                                                            
]]>
</programlisting>
</para>

<para>La commande <command>history</command> permet d'afficher les commandes dans l'ordre de leur mémorisation. 

<programlisting width="80"> 
<![CDATA[
$ history                                                                       
...
80  8:57    cp csh/Makefile Makefile.gen
81  9:03    more Makefile.gen
82  9:06    sed -e 's/SRCNAME=C-csh_n_tcsh/SRCNAME=/' Makefile.gen > Makefile   
83  9:07    xemacs createinf.sh
84  9:09    which mkdir
85  9:09    rm -rf html/ && make check && make html
86  9:10    ls -l csh/
87  9:12    echo $$
]]>
</programlisting> 
</para>

<para>Pour relancer une commande, il suffit de l'appeler par son numéro (relativement à l'historique) en la préfixant par le caractère !. Par exemple, si on veut relancer la commande 84, il suffit de faire :

<programlisting width="80">
<![CDATA[
$ !84                                                                           
which mkdir
/bin/mkdir
]]>
</programlisting>

</para>
      <para>
         <table>
	  <title>Quelques commandes de manipulation de l'historique</title>
	  <!-- one of (graphic mediaobject tgroup) -->
	  <tgroup cols="2" align='left'>

	    <thead>
	      <row>
		<!-- one of (entrytbl entry) -->
		<entry align='center'> Expression </entry>
		<entry align='center'> Sémantique </entry>
	      </row>
	    </thead>
	    <tbody>
	      <row>
		<!-- one of (entrytbl entry) -->
		<entry align='center'><command>!!</command></entry>
		<entry>Répéter la dernière commande.</entry>
	      </row>
	      
	      <row>
		<!-- one of (entrytbl entry) -->
		<entry align='center'><command>!</command><emphasis>n</emphasis></entry>
		<entry>Répéter la commande numéro <emphasis>n</emphasis>.</entry>
	      </row>

	      <row>
		<!-- one of (entrytbl entry) -->
		<entry align='center'><command>!-</command><emphasis>n</emphasis></entry>
		<entry>Répéter la <emphasis>n<superscript>ième</superscript></emphasis> précédent la dernière de l'historique, &ie; !-2 : avant dernière commande.</entry>
	      </row>
	      
	      <row>
		<!-- one of (entrytbl entry) -->
		<entry align='center'><command>!</command><emphasis>texte</emphasis></entry>
		<entry>Répéter la dernière commande commençant par <emphasis>texte</emphasis>.</entry>
	      </row>

	      <row>
		<!-- one of (entrytbl entry) -->
		<entry align='center'><command>!?</command><emphasis>texte</emphasis></entry>
		<entry>Répéter la dernière commande contenant <emphasis>texte</emphasis>.</entry>
	      </row>

	      <row>
		<!-- one of (entrytbl entry) -->
		<entry align='center'><command>!:</command><emphasis>n</emphasis></entry>
		<entry>Répéter le <emphasis>n<superscript>ième</superscript></emphasis> mot de la dernière commande.</entry>
	      </row>

	      <row>
		<!-- one of (entrytbl entry) -->
		<entry align='center'><command>!$</command></entry>
		<entry>Répéter le dernier mot de la dernière commande.</entry>
	      </row>

	      <row>
		<!-- one of (entrytbl entry) -->
		<entry align='center'><command>!*</command></entry>
		<entry>Répéter tous les arguments de la dernière commande.</entry>
	      </row>

	      <row>
		<!-- one of (entrytbl entry) -->
		<entry align='center'><command>^</command><emphasis>old</emphasis><command>^</command><emphasis>new</emphasis></entry>
		<entry>Répéter la dernière commande en commençant par remplacer la première occurence de <emphasis>old</emphasis> par <emphasis>new</emphasis>.</entry>
	      </row>

	      <row>
		<!-- one of (entrytbl entry) -->
		<entry align='center'><command>!</command><emphasis>n</emphasis><command>:s^</command><emphasis>old</emphasis><command>^</command><emphasis>new</emphasis></entry>
		<entry>Répéter la <emphasis>n</emphasis><superscript>ième</superscript> commande en commençant par remplacer la première occurence de <emphasis>old</emphasis> par <emphasis>new</emphasis>.</entry>
	      </row>
	      
	      <row>
		<!-- one of (entrytbl entry) -->
		<entry align='center'><command>!</command><emphasis>n</emphasis><command>:gs^</command><emphasis>old</emphasis><command>^</command><emphasis>new</emphasis></entry>
	<entry>Répéter la <emphasis>n</emphasis><superscript>ième</superscript> commande en commençant par remplacer toutes les occurences 
      de <emphasis>old</emphasis> par <emphasis>new</emphasis> (substitution globale).</entry>
	      </row>

	    </tbody>
	  </tgroup>
	</table>
</para>

      <para>Pour terminer, il peut être intéressant de positionner l'alias suivant dans son <filename>~/.cshrc</filename>.
<programlisting width="80">
<![CDATA[
alias h         'history -r \!* | less'                                         
]]>
</programlisting>  
</para>
      <qandaset defaultlabel='qanda'>
	<qandaentry>
	  <question>
	    <para>
            Que signifie donc cet alias ?
            </para>
	  </question>
	  <answer>
	    <para/>
	  </answer>
	</qandaentry>
      </qandaset>
    </sect2>




    <sect2>
      <title><foreignphrase>Completion</foreignphrase></title>
      
      <para> En <command>&fshell;</command> la <foreignphrase>completion</foreignphrase> est activée par le positionnement de la variable d'environnement <command>filec</command> (&cf; <quote><xref linkend="envvar"/></quote>). Ce mécanisme permet, selon le contexte, de compléter les noms de fichiers ou d'utilisateurs à partir de la saisie d'un préfixe suivi de la frappe du caractère <quote>ESC</quote>. <emphasis role='bold'>Le contexte par défaut étant celui de fichiers</emphasis>.</para>

      <para>Supposons, par exemple, que le contenu du répertoire courant soit le suivant :</para>
<para>
<programlisting width="80">
<![CDATA[
_merge.pl       check.pl             fdate.sh             mytest.pl
_pidof.pl       crlf.pl              gen-meta-index.pl    replace_header_html.pl
_split.pl       extract.pl           idle.pl              rotate.pl
_test.pl        extract_piste.sh     logfile-1.2.pl       rsync.pl
bidir.pl        fcomp.sh             mylock.sh
]]>
</programlisting> 
</para>
<para>Alors la séquence suivante :
<computeroutput>
<![CDATA[
$ ls l<ESC> 
]]>
</computeroutput>

est résolue en (seule correspondance possible) :
<computeroutput>
$ ls logfile-1.2.pl                                                           
</computeroutput>
</para>

<para>Tandis que la séquence ci-contre :
<computeroutput>
<![CDATA[
$ ls ext<ESC>                                                                 
]]>
</computeroutput>

est résolue partiellement en :
<computeroutput>
$ ls extract                                                                  
</computeroutput>
 suivit de l'émission d'un bip qui signale que cette expansion est incomplète puisque deux fichiers correspondent au préfixe saisi. La commande précédente suivie du <command>&lt;CTRL&gt;-D</command> permet d'obtenir l'ensemble des réponses potentielles :</para>

<para>
<programlisting width="80">
<![CDATA[
$ ls extract<CTRL>-D                                                            
extract.pl*       extract_piste.sh*
$ ls extract
]]>
</programlisting>
La saisie d'un seul caractère supplémentaire permet dans ce dernier cas de lever l'ambiguïté.  
</para>

      <para>L'utilisation du bip (sonnerie du terminal) pour signaler des erreurs ou des correspondances potentielles peut être désactivée par le positionnement de la variable <command>nobeep</command>. Enfin, il est possible de limiter les correspondances potentielles à la <foreignphrase>completion</foreignphrase> en positionnant la variable <command>fignore</command>. Dans l'exemple suivant, on exclut des correspondances possibles les fichiers suffixés en <command>.o</command>, <command>.out</command> et <command>*~</command>.</para>
<para>
<programlisting width="80">
<![CDATA[
$ set fignore = (.o .out *~)                                                    
]]>
</programlisting>
    </para>

<formalpara>
<title>Contexte utilisateur :</title>
<para>le mécanisme de <foreignphrase>completion</foreignphrase> peut être utilisé pour compléter les noms d'utilisateurs. Il faut utiliser le préfixe <command>~</command> (il change le contexte de la <foreignphrase>completion</foreignphrase>) : 
<programlisting width="80">
<![CDATA[
$ cd ~pa<ESC>                                                                   
$ cd ~pascal
]]>
</programlisting>
</para>
</formalpara>
    </sect2> 


<sect2>      
      <title>Navigation dans les répertoires </title>
      <sect3>
	<title>Commandes <command>cd</command></title>            
	<para>Supposons qu'un utilisateur ait souvent besoin de se rendre alternativement dans le répertoire <filename>/home/cvsroot/</filename> et dans son propre répertoire <filename>~/projets</filename>, il peut alors : </para>
	
	<itemizedlist>
	  <listitem><para>pour se rendre en <filename>/home/cvsroot/C-network/</filename>, taper : </para></listitem>
	</itemizedlist>

	<para>
<programlisting width="80">
<![CDATA[
$ cd /home/cvsroot/C-network                                                    
]]>
</programlisting>
</para>

	<itemizedlist>
	  <listitem><para>et pour se rendre en <filename>~/projets</filename>, taper :</para></listitem>
	</itemizedlist> 
	<para>
<programlisting width="80">
<![CDATA[
$ cd ~/projets                                                                  
]]>                                                              
</programlisting>
</para>


      <para>Mais, cet utilisateur peut aussi se simplifier la vie en positionnant la variable <command>cdpath</command>, ainsi :</para>
<para>
<programlisting width="80">
<![CDATA[
$ set cdpath = ( /home/cvsroot ~ )                                              
]]>
</programlisting>
</para>

	<para> Ainsi, il peut se contenter de :
<itemizedlist>
	    <listitem><para> taper dans le premier cas : </para></listitem>
	  </itemizedlist></para>
<para>
<programlisting width="80">
<![CDATA[
$ cd C-network                                                                  
/home/cvsroot/C-network
]]>
</programlisting>
</para>
    
	<itemizedlist>    
	  <listitem><para>et dans le second :</para></listitem>
	</itemizedlist>
	<para>
<programlisting width="80">
<![CDATA[
$ cd projets                                                                    
~/projets
]]>
</programlisting>
</para>
      
      </sect3>
      

      <sect3>
	<title>Pile de répertoires : <command>pushd</command>, <command>popd</command> et <command>dirs</command></title>
	<para> Une pile est une structure de données qui permet de mémoriser des entrées et dont la stratégie d'accès est de  type <foreignphrase><acronym>LIFO</acronym></foreignphrase> (<foreignphrase>Last In, First Out</foreignphrase>), &ie; on accède uniquement au sommet de la pile. </para>
<para>La pile des répertoires est gérée par les trois primitives suivantes : 
<itemizedlist>
	    <listitem><para> La commande <command>pushd</command> qui permet de changer de répertoire (comme <command>cd</command>), en conservant l'ancien répertoire dans la pile (il est empilé).</para>
	    </listitem>
	    
	    <listitem><para> La commande <command>popd</command> qui permet de changer de répertoire (comme <command>cd</command>), en dépilant le sommet de  la pile.</para>
	    </listitem>
	    
	    <listitem><para> La commande <command>dirs</command> qui permet d'afficher le contenu de la pile.</para>
	    </listitem>
	  </itemizedlist>
	</para>
	
<para>L'exemple suivant permet d'en comprendre le fonctionnement :
 
<programlisting width="80"> <!-- linenumbering='numbered' width='80'> -->
$ pwd <co id="com.pwd.1" linkends="pwd1" /> 
/usr/home/ikare/data/travail/Cours/ASR/Cours/Shells                        

$ pushd /usr/local/etc <co id="com.pushd"  linkends="pushd" /> 
/usr/local/etc ~/data/travail/Cours/ASR/Cours/Shells

$ pwd <co id="com.pwd.2" linkends="pwd2" /> 
/usr/local/etc

$ popd <co id="com.popd"  linkends="popd" /> 
~/data/travail/Cours/ASR/Cours/Shells 

$ pwd <co id="com.pwd.3"  linkends="pwd3" /> 
/usr/home/ikare/data/travail/Cours/ASR/Cours/Shells

$ pushd /usr/local/etc
/usr/local/etc ~/data/travail/Cours/ASR/Cours/Shells 

$ pwd 
/usr/local/etc

$ dirs -v <co id="com.dirsv"  linkends="dirsv" /> 
0       /usr/local/etc
1       ~/data/travail/Cours/ASR/Cours/Shells

$ more =1/shells.xml <co id="com.more"  linkends="more" />
<![CDATA[<?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 ccdil "ç">
<!ENTITY organ "Néotech III">

<!ENTITY unix   "<productname>Unix</productname>">
<!ENTITY Unix   "<emphasis>Unix</emphasis>">

<!ENTITY bsd    "<emphasis>BSD</emphasis>">
<!ENTITY ie     "<abbrev>i.e.</abbrev>">
<!ENTITY cf     "<abbrev>c.f.</abbrev>">
<!ENTITY shell  "<foreignphrase>shell</foreignphrase>">]]>

... encore plein de lignes...
</programlisting>

<calloutlist>
<callout arearefs="com.pwd.1" id="pwd1">
   <para>Affiche le chemin courant.</para>
</callout>

<callout arearefs="com.pushd" id="pushd">
<para> Se rend dans le répertoire spécifié et l'empile au sommet de la pile.</para>
</callout>

<callout arearefs="com.pwd.2" id="pwd2">
   <para>Affiche le chemin courant.</para>
</callout>

<callout arearefs="com.popd" id="popd">
<para> Dépile le sommet et se rend dans le répertoire indiqué.</para>
</callout>

<callout arearefs="com.pwd.3" id="pwd3">
   <para>Affiche le chemin courant.</para>
</callout>

<callout arearefs="com.dirsv" id="dirsv">
<para> Affiche le contenu de la pile, en commençant par le sommet.</para>
</callout>

<callout arearefs="com.more" id="more">
<para> Utilisation de la pile pour lire un fichier situé hors du répertoire courant.</para>
</callout>
</calloutlist>
</para>
      </sect3>
    </sect2>



<sect2>      
      <title> Gestion des processus </title>

      <sect3>
	<title>Les processus</title>
	
      <para>Un processus est l'instance d'un programme en exécution. C'est une structure de données qui contient du code statique, des données statiques et dynamiques et un environnement d'exécution. Un processus possède un cycle de vie marqué par des états comme l'exécution (<foreignphrase>runnable</foreignphrase>), la suspension, l'attente, le sommeil, l'état zombie... Pour se voir allouer des tranches de temps (<foreignphrase>time slice</foreignphrase>) d'exécution sur le <foreignphrase>CPU</foreignphrase>, un processus doit être dans l'état exécutable.</para> 

      <para>Chaque programme démarré par le <command>shell</command> nécessite la création d'un nouveau processus, on a ainsi une arborescence de processus, puisqu'une nouvelle instance ne possède qu'un seul parent. L'utilitaire <command>ps</command> permet d'obtenir un instantané des processus en cours</para>

<programlisting width="132">
$ > ps 
  PID <co id="com.pid" linkends="pid" />  TT <co id="com.tt" linkends="tt" />  STAT <co id="com.stat" linkends="stat" />      TIME<co id="com.time" linkends="time" /> COMMAND <co id="com.command" linkends="command" />
<![CDATA[
  945  p0  Is+    0:00,03 tcsh
 4241  p1  Ss     0:00,08 tcsh
 4588  p1  S      0:00,04 gv shells.pdf
 4592  p1  S      0:03,41 gs -sDEVICE=x11 -dTextAlphaBits=4 -dGraphicsAlphaBits=2 -dMaxBitmap=10000000 -dNOPLAT
 4605  p1  R+     0:00,00 ps
 4370  p2  Is+    0:00,03 tcsh
]]>
</programlisting>

<calloutlist>

<callout arearefs="com.pid" id="pid">
	  <para><foreignphrase>Process Identifier</foreignphrase>, identifiant (unique) du processus.</para>
</callout>

<callout arearefs="com.tt" id="tt">
	  <para><foreignphrase>TTy device</foreignphrase>, terminal d'exécution.</para>
</callout>

<callout arearefs="com.stat" id="stat">
	  <para><foreignphrase>STATus</foreignphrase>, état du processus</para>
</callout>

<callout arearefs="com.time" id="time">
	  <para><foreignphrase>TIME consumed</foreignphrase>, temps <foreignphrase>CPU</foreignphrase> consommé.</para>
</callout>

<callout arearefs="com.command" id="command">
	  <para>La commande exécutée.</para>
</callout>
</calloutlist>

      <para>Le système identifie chaque processus au moyen d'un entier appelé <foreignphrase>pid</foreignphrase>. Dans l'exemple précédent, la dernière ligne identifie le processus 4370 qui est un <command>shell</command> (<command>tcsh</command>) dans l'état <foreignphrase>idle</foreignphrase>, &ie; en sommeil depuis plus de 20 secondes, sur le terminal <command>/dev/ttyp2</command>.</para>

      <para>La consultation du <command>man 1 ps</command> permet d'obtenir une explication complète de la commande. Voici la sémantique &bsd; associée au premier caractère de la colonne <foreignphrase>STAT</foreignphrase> :

<table>
	  <title>Sens des éléments de la colonne <foreignphrase>STAT</foreignphrase></title>
	  <!-- one of (graphic mediaobject tgroup) -->
	  <tgroup cols="2" align='left'>


	    <thead>
	      <row>
		<!-- one of (entrytbl entry) -->
		<entry align='center'> Caractère </entry>
		<entry align='center'> Sémantique </entry>
	      </row>
	    </thead>
	    <tbody>
	      <row>
		<!-- one of (entrytbl entry) -->
		<entry align="center">D</entry>
		<entry>Processus en attente d'une E/S disque.</entry>
	      </row>
	      <row>
		<!-- one of (entrytbl entry) -->
		<entry align="center">I</entry>
		<entry>Processus en sommeil depuis plus de 20 secondes.</entry>
	      </row>
	      <row>
		<!-- one of (entrytbl entry) -->
		<entry align="center">R</entry>
		<entry>Processus en exécution sur le <foreignphrase>CPU</foreignphrase>.</entry>
	      </row>
	      <row>
		<!-- one of (entrytbl entry) -->
		<entry align="center">S</entry>
		<entry>Processus en sommeil depuis moins de 20 secondes.</entry>
	      </row>
	      <row>
		<!-- one of (entrytbl entry) -->
		<entry align="center">T</entry>
		<entry>Processus suspendu (stoppé)</entry>
	      </row>
	      <row>
		<!-- one of (entrytbl entry) -->
		<entry align="center">Z</entry>
		<entry>Processus Zombie</entry>
	      </row>
	    </tbody>
	  </tgroup>
	</table>
</para><para>Des caractères additionnels permettent d'avoir des informations supplémentaires, citons le <command>+</command> qui indique un processus d'avant plan (interactif [<foreignphrase>foreground</foreignphrase>]) parmi le groupe de processus contrôlé par un terminal.
</para>

	<para> La commande <command>ps l</command> (&cf; exemple suivant) permet d'obtenir plus de détails sur les processus. On y trouve les paramètres suivants : 
<itemizedlist>
	    <listitem><para>l'<foreignphrase>uid</foreignphrase> : propriétaire du processus,</para></listitem>
	    <listitem><para>le <foreignphrase>pid</foreignphrase> : identifiant du processus,</para></listitem> 
	    <listitem><para>le <foreignphrase>ppid</foreignphrase> : identifiant du père du processus,</para></listitem> 
	    <listitem><para>le <foreignphrase>cpu</foreignphrase> : estimation du temps <foreignphrase>CPU</foreignphrase> consommé,</para></listitem> 
	    <listitem><para>le <foreignphrase>pri</foreignphrase> : &ie; priorité d'ordonnancement,</para></listitem> 
	    <listitem><para>le <foreignphrase>nice</foreignphrase> : priorité assignée par <command>nice</command> ; la modification de cette valeur permet d'influer sur l'algorithme d'ordonnancement [<foreignphrase>scheduling</foreignphrase>],</para></listitem> 
	    <listitem><para>le <foreignphrase>vsz</foreignphrase> : donne la taille de la mémoire virtuelle utilisée (exprimée en kilo-octet),</para></listitem> 
	    <listitem><para>le <foreignphrase>rss</foreignphrase> : taille de la mémoire réelle utilisée (exprimée en kilo-octet).</para></listitem>
	    <listitem><para>le <foreignphrase>wchan</foreignphrase> : le canal d'attente, &ie; l'adresse d'une structure de données identifiant la ressource ou l'évènement pour lequel le processus est en attente,</para></listitem> 
	    <listitem><para>le <foreignphrase>state</foreignphrase> : état du processus parmi (R, S, I, Z ...), </para></listitem>
	    <listitem><para>le <foreignphrase>tt</foreignphrase> : le terminal associé au processus, </para></listitem>
	    <listitem><para>le <foreignphrase>time</foreignphrase> : temps <foreignphrase>cpu</foreignphrase> accumulé (utilisateur et système),</para></listitem> 
	    <listitem><para>enfin la commande elle-même.</para></listitem>
	  </itemizedlist>
</para>

<programlisting width="110">
<![CDATA[
$ ps l
  UID   PID  PPID CPU PRI NI   VSZ   RSS MWCHAN STAT  TT       TIME COMMAND
 2323   945   944   0   5  0  5248  3220 ttyin  Is+   p0    0:00,03 tcsh
 2323  4241  4240   0  20  0  5260  3340 pause  Ss    p1    0:00,08 tcsh
 2323  4588  4241   0  96  0  4236  3460 select S     p1    0:00,05 gv shells.pdf
 2323  4592  4588   0  96  0 17572 14648 select I     p1    0:03,41 gs -sDEVICE=x11 -dTextAlphaBits=4 -dGraphic
 2323  4653  4241   0  96  0  1580  1060 -      R+    p1    0:00,00 ps -l
 2323  4370  4369   0   5  0  5248  3268 ttyin  Is+   p2    0:00,03 tcsh

]]>
</programlisting>

	<para> L'invocation d'un programme déclenche un nouveau processus chargé de son exécution et pendant ce temps, le  &shell; (père du processus) est suspendu jusqu'à la terminaison de ce processus. On parle alors d'éxecution interactive (ou en avant-plan [<foreignphrase>foreground</foreignphrase>]). Il est évidement possible d'exécuter un processus de manière asynchrone [<foreignphrase>background</foreignphrase>], &ie; de permettre au &shell; d'exécuter de nouvelles commandes immédiatement. Il suffit pour se faire de postfixer la commande à exécuter de manière asynchrone par le caractère <quote>ampersand</quote> : &amp;. Voici un exemple (noter le numéro du processus : 20713) : 

<programlisting width="80">
<![CDATA[
$ fetchmail &                                                                   
[2] 20713
]]>
</programlisting>
</para>

      <para><command>&fshell;</command> a introduit la notion de suspension d'un processus interactif par la commande <command>^Z</command> (lire <command>&lt;CTRL&gt;-Z</command>). La reprise peut se faire de manière asynchrone (arrière plan) par la commande <command>bg</command> ou de manière interactive (avant plan) avec la commande symétrique <command>fg</command>. </para>

	<para>Pour finir, signalons la commande <command>top</command> qui permet d'avoir des informations en temps réel sur les processus (rafraîchissement toutes les 2 secondes). En voici un exemple tronqué :
<programlisting width="80">
<![CDATA[
last pid:  4689;  load averages:  0.00,  0.00,  0.00                                    up 0+04:20:56  12:34:16
75 processes:  1 running, 74 sleeping
CPU states:  1.9% user,  0.0% nice,  1.5% system,  0.0% interrupt, 96.6% idle
Mem: 222M Active, 214M Inact, 107M Wired, 1556K Cache, 111M Buf, 445M Free
Swap: 2048M Total, 2048M Free

  PID USERNAME    THR PRI NICE   SIZE    RES STATE    TIME   WCPU COMMAND
 4177 ikare         1  96    0 21764K 14140K select   0:05  0.49% xemacs-21.4.20
  898 root          1  96    0   208M   114M select  36:45  0.39% Xorg
  994 ikare         4  20    0 98472K 84764K kserel   2:30  0.00% firefox-bin
  919 ikare         1   8    0  2904K  2012K nanslp   1:16  0.00% wmcube
  918 ikare         1  96    0  2712K  1652K select   0:21  0.00% wmbattery
  922 ikare         1  96    0  5884K  2856K select   0:12  0.00% wmusic
  917 ikare         1   8    0  3012K  1932K nanslp   0:08  0.00% wmnd
  921 ikare         1   8    0  2872K  1912K nanslp   0:06  0.00% wmwave
  755 root          1  96    0  2944K  1660K select   0:04  0.00% hald-addon-storage
 4592 ikare         1  96    0 18180K 15188K select   0:04  0.00% gs
  925 ikare         1   8    0  4392K  2792K nanslp   0:03  0.00% mount.app
  510 root          1  96    0  1456K   852K select   0:03  0.00% moused
  746 haldaemon     1  96    0  5092K  3816K select   0:03  0.00% hald
  920 ikare         1   8    0  2868K  1868K nanslp   0:02  0.00% wmitime
  927 ikare         1  96    0  8224K  6544K select   0:01  0.00% fluxbox
  924 ikare         1  96    0  3752K  3000K select   0:01  0.00% xscreensaver
 4369 ikare         1  96    0  5656K  4704K select   0:01  0.00% aterm
  369 _pflogd       1 -58    0  1748K  1360K bpf      0:00  0.00% pflogd

]]>
</programlisting>
 </para>

      </sect3>
      
      <sect3>
	<title>Les signaux</title>
	<para>Les signaux sont une forme limitée de communication inter-processus. Ils permettent de prévenir les processus de l'occurence de certains évènements. Il est possible d'envoyer des signaux à des processus interactifs à partir du clavier. La commande suivante permet de connaître les associations clés/signaux :

<programlisting width="80">
<![CDATA[
$ stty -a                                                                       
speed 38400 baud; 50 rows; 132 columns;
lflags: icanon isig iexten echo echoe echok echoke -echonl echoctl
        -echoprt -altwerase -noflsh -tostop -flusho pendin -nokerninfo          
        -extproc
iflags: -istrip icrnl -inlcr -igncr ixon -ixoff -ixany imaxbel -ignbrk
        brkint -inpck ignpar -parmrk
oflags: opost onlcr -ocrnl -oxtabs -onocr -onlret
cflags: cread cs8 -parenb -parodd -hupcl -clocal -cstopb -crtscts
        -dsrflow -dtrflow -mdmbuf
cchars: discard = ^O; dsusp = ^Y; eof = ^D; eol = <undef>;
        eol2 = <undef>; erase = ^?; erase2 = ^@; intr = ^C; kill = ^U;
        lnext = ^V; min = 1; quit = ^\; reprint = ^R; start = ^Q;
        status = ^T; stop = ^S; susp = ^Z; time = 0; werase = ^W;
]]>
</programlisting>

Ainsi, la séquence &lt;CTRL&gt;-C (<command>^C</command>)  permet d'envoyer le signal de terminaison (<foreignphrase>INT signal</foreignphrase>), la séquence &lt;CTRL&gt;-\ (<command>^\</command>) permet d'envoyer un autre signal de terminaison (<foreignphrase>QUIT</foreignphrase>), la séquence &lt;CTRL&gt;-Z (<command>^Z</command>) permet d'envoyer le signal de suspension (<foreignphrase>TSTP</foreignphrase>). Par défaut, les deux premiers signaux (INT et QUIT) termine le processus, tandis que le troisième ne fait que suspendre l'éxecution, &ie; elle peut donc être reprise. Ce comportement par défaut peut cependant être redéfini au sein d'un processus. 
</para>
 
	<para>Sur une architecture <foreignphrase>4.4BSD</foreignphrase> (FreeBSD, NetBSD, OpenBSD) on trouve 31 signaux. La commande, improprement nommée <command>kill</command> (<computeroutput>man 1 kill</computeroutput>) permet d'envoyer des signaux à un processus. Sa syntaxe est la suivante : <command>kill &lt;signal&gt; &lt;pus&gt;</command>, où &lt;signal&gt; est le signal envoyé au processus de numéro &lt;pus&gt;</para>

	<para>La liste des signaux délivrable par la commande <command>kill</command> peut être obtenue de la manière suivante : 
<programlisting width="80">
<![CDATA[
$ kill -l                                                                       
HUP INT QUIT ILL TRAP ABRT EMT FPE KILL BUS SEGV SYS PIPE ALRM TERM URG STOP     
TSTP CONT CHLD TTIN TTOU IO XCPU XFSZ VTALRM PROF WINCH INFO USR1 USR2 
]]>
</programlisting>

Parmi ces signaux, deux ne peuvent être ni ignorés, ni détournés. Il s'agit du <command>KILL</command> (terminaison) et du <command>STOP</command> (suspension ou stop)  (à ne pas confondre avec le <command>TSTP</command> vu précédemment).  
</para>

      </sect3>
      <sect3>
	<title>Jobs</title>
	<para>Cette notion inventée par la branche <emphasis>BSD</emphasis> d'&unix; et introduite par <command>&fshell;</command> est désormais disponible sur toutes les distributions &unix; <emphasis>libres</emphasis>.</para>

	<para>Un <foreignphrase>job</foreignphrase> est soit un processus, soit un groupe de processus lancé par le &shell;. Un <foreignphrase>job</foreignphrase> peut être suspendu, redémarré, terminé, executé interactivement ou de manière asynchrone. Le &shell; sait gérer plusieurs <foreignphrase>jobs</foreignphrase> simultanément, toutefois à un instant donné seul un <foreignphrase>job</foreignphrase> peut avoir accès au terminal. Les <foreignphrase>jobs</foreignphrase> sont intéressants dès que les processus qu'ils contrôlent ont une durée de vie de quelques secondes. Analysons la séquence suivante : 


<programlisting width="80">
$ su  <co id="com.su" linkends="su" /> 
$ id
uid=0(root) gid=0(wheel) groups=0(wheel), 5(operator)

$ suspend <co id="com.susp" linkends="susp" /> 

Interrompu (Signal)
$ jobs <co id="com.job1" linkends="job1" />
[1]  + Interrompu (Signal)           su
[2]  - Tourne                        gv data/travail/Cours/ASR/Cours/Shells/shells.pdf

$ du -s -h /usr &amp; <co id="com.async" linkends="async" />
[3] 
$ ls50G    /usr/home id="com.rep" linkends="rep" />
[3]    Exit 1                 du -s -h /usr <co id="com.exit" linkends="exit" />
$ ls /usr/home
ikare   ivan

$ stty tostop <co id="com.async2" linkends="async2" />
$ du -s -h /usr/home/ &amp;

...

$ jobs
[1]  - Interrompu (Signal)           su
[2]    Tourne                        gv data/travail/Cours/ASR/Cours/Shells/shells.pdf
[3]  + Sortie tty suspendue          du -s -h /usr  <co id="com.notif" linkends="notif" />

$ %3 <co id="com.rep2" linkends="rep2" />
du -s -h /usr
50G    /usr

$ jobs
[1]  + Interrompu (Signal)           su
[2]  - Tourne                        gv data/travail/Cours/ASR/Cours/Shells/shells.pdf


$ %1
# exit <co id="com.rep3" linkends="rep3" />
$ jobs
[2]  - Tourne                        gv data/travail/Cours/ASR/Cours/Shells/shells.pdf
</programlisting>
<calloutlist>
	    <callout arearefs="com.su" id="su">
	      <para>Changement d'identité utilisateur, passe sous root</para>
	    </callout>

	    <callout arearefs="com.susp" id="susp">
	      <para>Suspension du processus et restauration de l'identité précédente.</para>
	    </callout>

	    <callout arearefs="com.job1" id="job1">
	      <para>Liste des <foreignphrase>jobs</foreignphrase> en cours;</para>
	    </callout>

	    <callout arearefs="com.async" id="async">
	      <para>Lancement d'une nouvelle commande, &ie; un processus de manière asynchrone, celui ci écrira son éventuel résultat sur la sortie standard, sans se préoccuper de ce qu'il peut se passer !</para>
	    </callout>

	    <callout arearefs="com.rep" id="rep">
	      <para>Le résultat de la commande <command>du</command> survient au moment où l'utilisateur tape sa commande <command>ls</command> et pertube donc son affichage. </para>
	    </callout>
	    
	    <callout arearefs="com.exit" id="exit">
	      <para> Terminaison du processus. La commande <command>ls</command> s'affiche alors.</para>
	    </callout>

	    <callout arearefs="com.async2" id="async2">
	      <para>Pour éviter le mélange précédent, nous bloquons l'écriture du résultat de la commande sur le terminal.</para>
	    </callout>

	    <callout arearefs="com.rep2" id="rep2">
	      <para>Le comportement du processus change, l'utilisateur est informé (variable <command>notify</command> de &fshell;, &cf; <quote><xref linkend="envvar"/></quote>) que le <foreignphrase>job</foreignphrase> 3 est prêt à imprimer son résultat (il est suspendu jusqu'à ce qu'il soit autorisé à la faire).</para>
	    </callout>

	    <callout arearefs="com.notif" id="notif">
	      <para>On rappelle le <foreignphrase>job</foreignphrase> 3, ce qui lui permet d'afficher son résultat.</para>
	      <para>Un <foreignphrase>job</foreignphrase> asynchrone qui veut lire sur l'entrée standard alors que ce canal n'a pas été redirigé est toujours suspendu. Il faut le relancer de manière interactive pour qu'il puisse collecter ses données sur l'entrée standard.</para>
	    </callout>

	    <callout arearefs="com.rep3" id="rep3">
	      <para>On rappelle le <foreignphrase>job</foreignphrase> 2 et on le termine explicitement par un <command>exit</command>. Il reste alors un seul <foreignphrase>job</foreignphrase> en exécution asynchrone.</para>
	    </callout>
</calloutlist>
</para>

	<para>La liste des <foreignphrase>jobs</foreignphrase> en cours est donné par la commande <command>jobs</command>. </para>
	<para>Le caractère % en première position dénote un <foreignphrase>job</foreignphrase>. </para>
	<para>Le tableau suivant (&cf; <quote><xref linkend="tab05"/></quote>) récapitule les différentes manières de référencer un <foreignphrase>job</foreignphrase>. 
<table id="tab05">
	    <title> référencement des <foreignphrase>jobs</foreignphrase></title>
	    <!-- one of (graphic mediaobject tgroup) -->
	    <tgroup cols="2" align='left'>

	      <thead>
		<row>
		  <!-- one of (entrytbl entry) -->
		  <entry> Expression </entry>
		  <entry> Sémantique </entry>
		</row>
	      </thead>
	      <tbody>
		<row>
		  <!-- one of (entrytbl entry) -->
		  <entry>%n</entry>
		  <entry><foreignphrase>job</foreignphrase> numéro <emphasis>n</emphasis>.</entry>
		</row>
		<row>
		  <!-- one of (entrytbl entry) -->
		  <entry>%str</entry>
		  <entry><foreignphrase>job</foreignphrase> commençant par la chaine <emphasis>str</emphasis>.</entry>
		</row>
		<row>
		  <!-- one of (entrytbl entry) -->
		  <entry>%?str</entry>
		  <entry><foreignphrase>job</foreignphrase> contenant la chaine <emphasis>str</emphasis>.</entry>
		</row>
	      </tbody>
	    </tgroup>
	  </table>
</para>
	
	<para>Le tableau suivant (&cf; <quote><xref linkend="tab06"/></quote>) donne les commandes de contrôle d'un <foreignphrase>job</foreignphrase>. 

<table id="tab06">
	    <title> Commandes contrôlant les <foreignphrase>jobs</foreignphrase></title>
	    <!-- one of (graphic mediaobject tgroup) -->
	    <tgroup cols="2" align='left'>
             
	      <thead>
		<row>
		  <!-- one of (entrytbl entry) -->
		  <entry> Expression </entry>
		  <entry> Sémantique </entry>
		</row>
	      </thead>
	      <tbody>
		<row>
		  <!-- one of (entrytbl entry) -->
		  <entry><command>bg [name]</command></entry>
		  <entry><para>Place le job <emphasis>name</emphasis> en exécution asynchrone. </para>
                         <para>Si l'argument <emphasis>name</emphasis> n'est pas précisé, la commande s'applique au <foreignphrase>job</foreignphrase> courant.</para></entry>
		</row>
		
		<row>
		  <!-- one of (entrytbl entry) -->
		  <entry><command>name &amp;</command></entry>
		  <entry>Place le job <emphasis>name</emphasis> en exécution asynchrone.</entry>
		</row>
		
		<row>
		  <!-- one of (entrytbl entry) -->
		  <entry><command>fg [name]</command></entry>
		  <entry> <para>Place le job <emphasis>name</emphasis> en exécution interactive.</para>
                          <para>Si l'argument <emphasis>name</emphasis> n'est pas précisé, la commande s'applique au <foreignphrase>job</foreignphrase> courant.</para>
                  </entry>
		</row>

		<row>
		  <!-- one of (entrytbl entry) -->
		  <entry><command>name</command></entry>
		  <entry>Place le job <emphasis>name</emphasis> en exécution interactive.</entry>
		</row>

		<row>
		  <!-- one of (entrytbl entry) -->
		  <entry><command>stop name</command></entry>
		  <entry>Suspend le job <emphasis>name</emphasis>.</entry>
		</row>

	      </tbody>
	    </tgroup>
	  </table>
</para>

	<para>Enfin, la commande <command>kill</command> permet aussi d'envoyer des signaux aux <foreignphrase>jobs</foreignphrase>, en utilisant le même référencement des jobs qu'en <quote><xref linkend="tab05"/></quote>. Ainsi, la commande suivante met fin au <foreignphrase>job</foreignphrase> 1 : 
<programlisting width="80">
<![CDATA[
$ kill -TERM %1                                                                 
]]>
</programlisting>
</para>

	<important>
	  <para>En <command>&fshell;</command>, comme en <command>tcsh</command> les processus asynchrones ne sont pas affectés par un <command>logout</command> puisqu'il n'y a pas d'envoi du signal <foreignphrase>HUP</foreignphrase> à l'exécution du <command>logout</command>. </para>
	  <para>Corollaire : pas besoin de la commande <command>nohup</command> des autres <foreignphrase>shells</foreignphrase> (tel <emphasis>GNU/Bash</emphasis>).</para>
	</important>
      </sect3>


      <sect3>
	<title><command>limit</command></title>
	<para>Cette commande a pour objet de définir des limites à la consommation des ressources du système par les processus. Il s'agit d'un intervalle définit par une borne haute (<foreignphrase>hard limits</foreignphrase> : qui ne peut être modifiée qu'à la baisse, sauf par le <emphasis>super</emphasis>-utilisateur et une borne basse (<foreignphrase>current limits</foreignphrase> : qui peut être accrue jusqu'aux valeurs de la borne haute).</para>
      
      <para>
<programlisting width="80">
<![CDATA[
$ limit         # affichage des limites courantes                               
cputime         unlimited
filesize        unlimited
datasize        262144 kbytes
stacksize       262144 kbytes
coredumpsize    0 kbytes
memoryuse       unlimited
vmemoryuse      unlimited
descriptors     2048 
memorylocked    unlimited
maxproc         1024 
sbsize  unlimited

$ limit coredumpsize 1024 # augmenter la limite basse d'un fichier core à 1024k 

$ limit maxproc 2048 # augmenter le nb max de proc concurrents
limit: maxproc: Can't set limit (Operation not permitted)

$ limit maxproc 512    # augmenter le nb max de proc concurrents (lim. cour.)
$ limit -h maxproc 784 # augmenter le nb max de proc concurrents (lim. hautes)

$ limit         # affichage des limites courantes                               
cputime         unlimited
filesize        unlimited
datasize        262144 kbytes
stacksize       262144 kbytes
coredumpsize    1024 kbytes
memoryuse       unlimited
vmemoryuse      unlimited
descriptors     2048 
memorylocked    unlimited
maxproc         512 
sbsize  unlimited

$limit -h       # affichage des limites hautes                               
cputime         unlimited
filesize        unlimited
datasize        262144 kbytes
stacksize       262144 kbytes
coredumpsize    unlimited
memoryuse       unlimited
vmemoryuse      unlimited
descriptors     2048 
memorylocked    unlimited
maxproc         784 
sbsize  unlimited
]]>
</programlisting>
</para>
    </sect3>

    </sect2>



<sect2 id="sect_redirection_comm">      
      <title>Redirection de commandes</title>
      <para> Rapellons que, sous &unix; en général et sous <emphasis role="bold">BSD</emphasis> en particulier, il existe trois canaux d'E/S standard : 
      <itemizedlist>
	<listitem><para>L'entrée standard [<foreignphrase>stdin</foreignphrase>] associée au fd [<foreignphrase>file descriptor</foreignphrase>] <emphasis role="bold">0</emphasis> liée traditionnellement au clavier.</para></listitem>
	<listitem><para>La sortie standard [<foreignphrase>stdout</foreignphrase>] associée au fd <emphasis role="bold">1</emphasis>, liée traditionnellement à l'écran du terminal.</para></listitem>
	<listitem><para>La sortie standard d'erreur  [<foreignphrase>stderr</foreignphrase>] associée au fd <emphasis role="bold">2</emphasis>, liée traditionnellement à l'écran du terminal.</para></listitem>
      </itemizedlist>

Formellement, un descripteur de fichier est un entier non signé utilisé par les processus pour référencer les canaux d'E/S.
      </para>
      
      <para>La puissance et la flexibilité du concept des canaux standards  d'E/S tient essentiellement au fait que le &shell; peut rediriger ces canaux aussi bien sur des fichiers, que l'écran ou le clavier.</para> 


<para> 
<table id="redirec">
	  <title>Redirections</title>
	  <tgroup cols="2">

	    
	    <thead valign="middle">
	      <row>
		<entry align="center">Symbole</entry>
		<entry align="center">Sémantique</entry>
	      </row>
	    </thead>
	    
	    <tbody>	      	     	    		
	      <row>
		<entry><command>&gt;</command> &lt;fnom&gt;</entry>
		<entry>La sortie standard est redirigée dans le fichier &lt;fnom&gt;. S'il existait, son contenu est perdu et sinon il est créé.</entry>
	      </row>

	      <row>
		<entry><command>&gt;&gt;</command> &lt;fnom&gt;</entry>
		<entry>La sortie standard est redirigée dans le fichier &lt;fnom&gt;, ouvert en mode ajout s'il existait, sinon il est créé.</entry>
	      </row>


	      <row>
		<entry><command>&gt;&amp;</command> &lt;fnom&gt;</entry>
		<entry>La sortie d'erreur est redirigée dans le fichier &lt;fnom&gt;. S'il existait, son contenu est perdu et sinon il est créé.</entry>
	      </row>

	      <row>
		<entry><command>&gt;&gt;&amp;</command> &lt;fnom&gt;</entry>
		<entry>La sortie d'erreur est redirigée dans le fichier &lt;fnom&gt;, ouvert en mode ajout s'il existait, sinon il est créé.</entry>
	      </row>


	      <row>
		<entry><command>&lt;</command> &lt;fnom&gt;</entry>
		<entry>L'entrée standard est le fichier &lt;fnom&gt;.</entry>
	      </row>
	      
	      <row>
		<entry><command>&lt;&lt;</command> &lt;mot&gt;</entry>
		<entry>Lit les entrées du &shell; jusqu'à une ligne commençant (et contenant uniquement) le mot &lt;mot&gt; qui agit comme un marqueur de fin.</entry>
	      </row>
	    </tbody>
	  </tgroup>
	</table>


</para>


<para>Le positionnement de la variable interne <varname>noclobber</varname>, permet d'éviter l'écrasement des fichiers existants dans le cas de l'utilisation des commandes de redirection <command>&gt;</command> et <command>&gt;&amp;</command>. De plus les commandes  <command>&gt;&gt;</command> et <command>&gt;&gt;&amp;</command> ne peuvent être exécutées que sur des fichiers existants.</para>

      <para>Enfin, la sémantique initiale des commandes de redirection (après activation de <varname>noclobber</varname>) peut être explicitement restituée en utilisant le symbole <command>!</command>. Ainsi, les commandes <command>&gt;!</command>, <command>&gt;&gt;!</command>, <command>&gt;&amp;!</command> et <command>&gt;&gt;&amp;!</command> ont un comportement identique à leurs homologues du tableau précédent (&ie; sans le <command>!</command>, &cf; <quote><xref linkend="redirec"/></quote>).

<programlisting width="80">
<emphasis>EXEMPLES :</emphasis>
<![CDATA[
$ cat > file.txt << fin_de_saisie                                               
>> première ligne
>> puis une 2e
>> Encore une autre !
>> C'est pas fini ...
>> fin_de_saisie

$  ll file.txt
-rw-r--r--  1 ikare  ikare  23 20 avr 14:37 file.txt

$ cat < file.txt  # équivalent à cat file.txt
première ligne
puis une 2e
Encore une autre !
C'est pas fini ...

$ ( find /home -name "*~" -print > fout ) >& ferr
                  # séparer les sorties standard (> fout) et d'erreur (>& ferr) 
$ cat fout        # les résultats
/usr/local/www/data/tyle_docbook.css~
/usr/local/www/data/docbook_ikare.css~
/usr/local/www/data/_my_style.css~
/usr/local/www/data/freebsd.css~
/usr/local/www/data/styleswitcher.js~
/usr/local/www/data/style_docbook.css~
/usr/local/www/data/style.css~
/usr/local/www/kurzweg/Cnfpt2006/index.php~
/usr/local/www/kurzweg/bts/admin/ccf.php~
/usr/local/www/kurzweg/bts/admin/ccf_liste_stag.php~
/usr/local/www/kurzweg/bts/admin/ccf_stag.php~
/usr/local/www/kurzweg/cnam/nfa001/haut.php~
/usr/local/www/kurzweg/styleswitcher.js~
/usr/local/www/kurzweg/_my_style.css~
/usr/local/www/kurzweg/style.css~
/usr/local/www/kurzweg/style_docbook.css~
/usr/local/www/kurzweg/tyle_docbook.css~
/usr/local/www/kurzweg/docbook_ikare.css~
/usr/local/www/kurzweg/freebsd.css~


$ cat ferr        # les erreurs
find: /usr/local/etc/cups/ssl: Permission denied
]]>
</programlisting>
</para>
    </sect2>





<sect2>      
      <title> Tubes [<foreignphrase>Pipelines</foreignphrase>] </title>
      <para>
Le mécanisme de <foreignphrase>pipeline</foreignphrase> consiste à  rediriger la sortie d'une commande vers l'entrée d'une autre. D'un point de vue syntaxique nous avons la structure suivante :
<programlisting width="80">
<![CDATA[
<commandA> | <commandB>                                                         
]]>
</programlisting>
      
      <example id="ex_pipe">
	<title> Utilisation du mécanisme de <foreignphrase>pipeline</foreignphrase> </title>
	<para>
<programlisting width="80">
<![CDATA[
$ ls -l | sort -k 5n                                                            
]]>
</programlisting>

La sortie de la commande <command>ls -l</command> est redirigée vers l'entrée de la commande <command>sort -k 5n</command>.
</para>
      </example>
    </para>

      <qandaset defaultlabel='qanda'>
	<qandaentry>
	  <question>
	    <para>
            Que permet de réaliser la commande précédente ?
            </para>
	  </question>
	  <answer>
	    <para/> 
            <!-- tri numérique (ordre croissant) du répertoire (listing au format long) sur le 5e champ, i.e. la taille en octet --> 
	  </answer>
	</qandaentry>
      </qandaset>

      <para>
Enfin, en postfixant au tube ('|' ou encore <foreignphrase>pipe</foreignphrase>) l'<foreignphrase>ampersand</foreignphrase> (&amp;), il est possible de combiner les sorties standard et d'erreur vers l'entrée de la commande qui suit (le tube). 

<programlisting width="80">
<![CDATA[
<commandA> |& <commandB>                                                        
]]>
</programlisting>
</para>
    </sect2>

<sect2>
<title>Exercices</title>
<sect3>
	<title>Commandes de base, redirections et pipes</title>
<para>

<orderedlist>
	    <listitem>
	<para>Comment ajouter le contenu de fichier 1 à fichier 2?</para></listitem>
	    <listitem>
   <para> Combien y a t-il de processus actifs sur le système ? (Utilisez la commande ps)</para></listitem>
	    <listitem>
      <para> Combien d'utilisateurs sont connectés sur le système? Afficher la liste des utilisateurs connectés triée par ordre alphabétique,  puis selon l'heure de connexion</para></listitem>
	    <listitem>
      <para> Combien le répertoire /usr/local/etc a-t-il de sous répertoire? (ls -F)</para></listitem>
	    <listitem>
      <para>Comment afficher la liste des fichiers contenus dans le répertoire /usr/local/bin, triés par ordre croissant sur le numéro d'inode (ls -i) ? Comment afficher ce résultat sur une imprimante ?</para></listitem>
	    <listitem>
      <para>Afficher la liste des fichiers du répertoire courant par ordre de taille.</para></listitem>
	    <listitem>
      <para>Rechercher la chaîne erreur dans un fichier, sans tenir compte de la différence entre les lettres majuscules et minuscules.</para></listitem>
	    <listitem>
	<para>Construisez un fichier ~/tmp/foo contenant l'ensemble des variables du shell</para></listitem>
</orderedlist>
</para>
</sect3>
</sect2>

</sect1>







<!-- 3e partie -->
  <sect1>

    <title>Structures de Contrôle &amp; autres éléments algorithmiques</title>

    <para>Ces structures algorithmiques sont utilisées dans les scripts &shell;s. Pour rédiger un script &shell; (ici, en &fshell2;), il faut :
<orderedlist>
	<listitem><para>Créer le fichier avec un éditeur de texte (<filename>sample.sh</filename>). La première ligne doit commencer avec le prologue [<foreignphrase>shebang</foreignphrase>] :  <command>#!/bin/tcsh</command>. </para></listitem>
	<listitem><para>Lui attribuer la permission d'exécution sur le fichier créé (<computeroutput>chmod +x sample.sh</computeroutput>).</para></listitem>
	<listitem><para>Enfin, pour l'exécuter il suffit de taper le nom du fichier, puisque c'est désormais une nouvelle commande (si on est dans le répertoire courant de cette commande, il suffit de taper <computeroutput>./sample.sh</computeroutput>).</para></listitem>
      </orderedlist>
Nous donnons dans ce qui suit, quelques exemples de scripts &shell;s (&fshell;). 
    </para>
    
    <sect2>      
      <title>Alternatives</title>
<!-- IF -->
      <sect3>
	<title> La structure alternative <command>if</command></title>
	<para> Cette structure permet l'exécution conditionnelle d'une instruction. Voici sa syntaxe :</para> 
	<para>
<programlisting width="80">
<![CDATA[
if ( <condition> ) then                                                         
  <liste instructions>
else if ( <condition> ) then
  <liste instructions>
else if ( <condition> ) then
  <liste instructions>
else
  <liste instructions>
endif
]]>
</programlisting>
</para>

<para>
<example id="ex_if">
	    <title>Utilisation du if</title>
<programlisting width="80">
&_fcomp;
</programlisting>
	  </example>
<example>
	    <title> Résultat du code de <xref linkend="ex_if"/> </title>
<programlisting width="80">
<![CDATA[
$ ~/bin/fcomp.sh                                                                
usage : /home/pascal/bin/fcomp.sh file1 file2
compare deux fichiers file1 et file2 et dit s'il sont identiques ou differents. 

$ ~/bin/fcomp.sh ~/bin/fdate.sh ~/bin/fcomp.sh
Les fichiers /home/pascal/bin/fdate.sh et /home/pascal/bin/fcomp.sh sont differe
nts.

$ ~/bin/fcomp.sh ~/bin/fdate.sh /etc/shadow
Une erreur est survenue !
]]>
</programlisting>
	</example>
</para>
      </sect3>
<!-- END IF -->

<!-- SWITCH -->
<sect3>
	<title> La structure alternative <command>switch</command></title>
	<para> Cette structure permet l'exécution conditionnelle d'une instruction. </para> 
	<para>
<programlisting width="80">
<![CDATA[
switch ( <variable> )                                                           
  case motif1 :
         <liste instructions>
         breaksw

  case motif2 :
  case motif3 :
         <liste instructions>
         breaksw

  case motif4 :
         <liste instructions>

  case motif5 :
         <liste instructions>

  default:
         <liste instructions>

endsw
]]>
</programlisting>
</para>

<para>
<example id="ex_switch">
	    <title>Utilisation du switch</title>
<para>
<programlisting width="80">
&_fdate;
</programlisting>
</para>
	  </example>

<example>
	    <title> Résultat du code de <xref linkend="ex_switch"/> </title>
<programlisting width="80">
$ fdate.sh                                                                      
Sam 12 Avr 2003, 21:20:45 [RET]
</programlisting>
	</example>

</para>

      </sect3>
<!-- END SWITCH -->
    </sect2>




    <sect2>      
      <title>Boucles</title>
<!-- WHILE -->
      <sect3>
	<title> Boucle <command>while</command></title>
	<para> Il s'agit de l'instruction standard qui permet d'exécuter le corps de la boucle tant que la condition d'entrée est vérifiée (valeur évaluée à vrai). </para>
	<para>
<programlisting width="80">
<![CDATA[
while ( <condition> )                                                           
  <corps_de_boucle>
end
]]>
</programlisting>
</para>

<para>
<example id="ex_while">
	    <title>Utilisation du while</title>
<programlisting width="80">
<![CDATA[
#!/bin/csh 
# ~/bin/test.sh                                                                 

set ind=1

while ( $ind < 11 )
  @ indcar = $ind * $ind
  echo $ind "  " $indcar
  @ ind++
end
]]>
</programlisting>
	  </example>
<example>
	    <title> Résultat du code de <xref linkend="ex_while"/> </title>
<programlisting width="80">
<![CDATA[
$ ~/bin/test.sh                                                                 
1     1                                                                         
2     4
3     9
4     16
5     25
6     36
7     49
8     64
9     81
10     100
]]>
</programlisting>
	</example>
</para>

      </sect3>
<!-- END WHILE -->

<!-- REPEAT -->      
      <sect3>
	<title>Boucle <command>repeat</command> </title>
	<para> Cette instruction permet de répéter un nombre entier de fois une même commande.</para>
	<para>
<programlisting width="80">
<![CDATA[
repeat <nombre_de_fois> <commande>                                              
]]>
</programlisting>
</para>

<para>
<example id="ex_repeat">
	    <title> Utilisation et résultat du <command>repeat</command> </title>
<programlisting width="80">
<![CDATA[
$ repeat 3 echo "hello, world !"                                                
hello, world !                                                                  
hello, world !
hello, world !
]]>
</programlisting>
	  </example>
</para>

      </sect3>
<!-- END REPEAT -->

<!-- FOREACH -->
    <sect3>
	<title> Boucle <command>foreach</command></title>
	<para> Cette instruction permet de traiter en séquence tous les éléments d'une liste.</para>
	<para>

<programlisting width="80">
<![CDATA[
foreach <variable> ( <liste_de_valeur> )                                        
  <corps_de_boucle>
end
]]>
</programlisting>
</para>

<para>
<example id="ex_foreach">
	    <title> Utilisation du <command>foreach</command> </title>
<programlisting width="80">
<![CDATA[
#!/bin/csh
# ~/bin/test.sh                                                                 

foreach i ( 1 2 3 4 5 6 7 8 9 )                                                 
  @ m = $i * 2
  echo -n " $m"
end
echo
]]>
</programlisting>
	  </example>

<example>
	    <title> Résultat du code de <xref linkend="ex_foreach"/> </title>
<programlisting width="80">
<![CDATA[
$ ~/bin/test.sh                                                                 
2 4 6 8 10 12 14 16 18                                                          
$
]]>
</programlisting>
	</example>
</para>

      </sect3>
<!-- END FOREACH -->
    </sect2>

    
     <sect2>
      <title>Variables utilisateurs</title>

      <para>Ce sont les variables que les utilisateurs peuvent définir. Le &shell; étant un langage interprété non typé, aucune déclaration n'est nécessaire et la même variable peut contenir tour à tour une chaîne de caractères, un entier, ou un vecteur (tableau d'éléments de type chaîne de caractères ou entier, indexé par des entiers, commençant à 1).</para>
      
      <formalpara>
	<title>Affectation</title>
	<para>Cette opération permet d'associer un contenu à une variable (le contenant). En &fshell; comme en &fshell2;,  l'affectation se fait en utilisant la commande interne <command>set</command> de la manière suivante :
<programlisting width="80">
<emphasis>EXEMPLE :</emphasis>
<![CDATA[
$ set myvar1 = 10                                                               
$ set myvar2 = "chaine de caractère"
$ 
]]>
</programlisting>
</para>
      </formalpara>

      <formalpara>
	<title>Accès au contenu</title>
	<para>L'accès au contenu de la variable se fait en préfixant le nom de la variable par le symbole <emphasis role="bold">$</emphasis>.
<programlisting width="80">
<emphasis>EXEMPLE (SUITE) :</emphasis>
<![CDATA[
$ echo $myvar1                                                                  
10
$ echo $myvar2
chaine de caractère

$ echo myvar1     # omission du méta-caractère $
myvar1            # echo affiche le mot myvar1
]]>
</programlisting>

On peut aussi encadrer la variable par les symboles <emphasis role="bold">{</emphasis> et <emphasis role="bold">}</emphasis> avant de la préfixer par le symbole <emphasis role="bold">$</emphasis> :
<programlisting width="80">
<emphasis>EXEMPLE (SUITE) :</emphasis>
<![CDATA[
$ set si  = "pas "                                                              
$ echo "c'est vraiment $sidrôle"
sidrôle: Undefined variable.   # le $ porte ici sur le mot sidrôle et non sur si
$ echo "c'est vraiment ${si}drôle"
c'est vraiment pas drôle
$
]]>
</programlisting>

<note><para>L'accès à une variable non définie produit (sauf rares exceptions) une erreur (en &fshell;, comme en &fshell2;).</para></note>
</para>
      </formalpara>

 <formalpara>
	<title>Effacer une variable</title>
	<para>Cette opération permet de libérer la case mémoire occupée par la variable. Cela se fait en &fshell; comme en &fshell2;, en utilisant la commande interne <command>unset</command> de la manière suivante :
<programlisting width="80">
<emphasis>EXEMPLE (SUITE) :</emphasis>
<![CDATA[
$ echo $myvar1                                                                  
10
$ unset myvar1
$ echo $myvar1
myvar1: Undefined variable.
$ 
]]>
</programlisting>
</para>
      </formalpara>


      <formalpara>
	<title>Variable de type vecteur</title>
	<para>Voici un exemple :
<programlisting width="80">
<emphasis>CODE :</emphasis>
<![CDATA[
#!/bin/csh
# ~/bin/testvect.sh

set vect = ( 2 -2 4 -4 6 -6 8 -8 10 -10 ) 

# afficher les éléments du vecteur vect, élément par élément                    
set i = 1
set sum = 0
echo " -  Affichage élément par élément"
while ( $i <= ${#vect} ) 
    echo '$vect[' $i '] = ' $vect[$i]
    @ sum = $sum + $vect[$i]
    @ i++
end

echo " - Somme des elements = " $sum

set j = 5
echo "Voici le vecteur vect (${#vect} éléments)         : " $vect[1-]
echo "Voici les $j premiers éléments du vecteur    : " $vect[-$j]
echo "Voici les derniers éléments à partir du $j e : " $vect[$j-]

# fin du script

]]>
<emphasis>EXEMPLE :</emphasis>
<![CDATA[
$ ./testvect.sh                                                                 
 -  Affichage élément par élément
$vect[ 1 ] =  2
$vect[ 2 ] =  -2
$vect[ 3 ] =  4
$vect[ 4 ] =  -4
$vect[ 5 ] =  6
$vect[ 6 ] =  -6
$vect[ 7 ] =  8
$vect[ 8 ] =  -8
$vect[ 9 ] =  10
$vect[ 10 ] =  -10
 - Somme des elements =  0
Voici le vecteur vect (10 éléments)         :  2 -2 4 -4 6 -6 8 -8 10 -10
Voici les 5 premiers éléments du vecteur    :  2 -2 4 -4 6
Voici les derniers éléments à partir du 5 e :  6 -6 8 -8 10 -10

$
]]>
</programlisting>
</para>
      </formalpara>


      <formalpara>
	<title>Modificateurs de variables</title>
	<para>Les modificateurs [<foreignphrase>modifiers</foreignphrase>] suivants peuvent être appliqués aux variables. On travaillera avec l'exemple (un vecteur) suivant :

<programlisting width="80">
<![CDATA[
$ set mypath = ( /usr/local/src/foo.c /usr/src/bar.cc )   # un vecteur de path  
]]>
</programlisting>


<table>
	    <title>Clé de modification</title>
	    <tgroup cols="3">


	      <thead valign="middle">
		<row>
		  <entry align="center">Clé</entry>
		  <entry align="center">Sémantique</entry>
		  <entry align="center">Exemple</entry>
		</row>
	      </thead>

	      <tbody>	      	     	    		
		<row>
		  <entrytbl cols="1">
		    <tbody>
		      <row>
			<entry><command>:h</command>&nbsp;&nbsp;
			       <command>:gh</command></entry>
		      </row>
		    </tbody>
		  </entrytbl>

		  <entrytbl cols="1">
		    <tbody>
		      <row>
			<entry>interprète le contenu de la variable comme un nom de fichier &unix;</entry> 
			<entry>et en donne le début, &ie; la partie avant le dernier /</entry>
		      </row>
		    </tbody>
		  </entrytbl>

		  <entry>
<programlisting width="36">
<![CDATA[
$ echo $mypath:h                    
/usr/local/src /usr/src/bar.cc
$ echo $mypath:gh
/usr/local/src /usr/src
]]>
</programlisting>
                  </entry>
		</row>

		<row>
		  <!-- <entry><command>:t</command></entry> -->
		  <entrytbl cols="1">
		    <tbody>
		      <row>
			<entry><command>:t</command>&nbsp;&nbsp;
			       <command>:gt</command></entry>
		      </row>
		    </tbody>
		  </entrytbl>
		  
		   <entrytbl cols="1">
		    <tbody>
		      <row>
			<entry>interprète le contenu de la variable comme un nom de fichier &unix; 
			et en donne la fin, &ie; la partie après le dernier /</entry>
		      </row>
		    </tbody>
		  </entrytbl>

		  <entry>
<programlisting width="36">
<![CDATA[
$ echo $mypath:t                    
foo.c /usr/src/bar.cc
$ echo $mypath:gt
foo.c bar.cc
]]>
</programlisting>
</entry>
		</row>
		
		<row>
		  <!--  <entry><command>:r</command></entry> -->
		  <entrytbl cols="1">
		    <tbody>
		      <row>
			<entry><command>:r</command>&nbsp;&nbsp;
			       <command>:gr</command></entry>
		      </row>
		    </tbody>
		  </entrytbl>

		  <entry>supprime l'extension en fin de variable.</entry>
		  <entry>
<programlisting width="36">
<![CDATA[
$ echo $mypath:r
/usr/local/src/foo /usr/src/bar.cc  
$ echo $mypath:gr
/usr/local/src/foo /usr/src/bar
]]>
</programlisting>
</entry>
		</row>

		<row>
		  <!-- <entry><command>:e</command></entry> -->
		  <entrytbl cols="1">
		    <tbody>
		      <row>
			<entry><command>:e</command>&nbsp;&nbsp;
			       <command>:ge</command></entry>
		      </row>
		    </tbody>
		  </entrytbl>
		  <entry>donne l'extension correspondant à la fin de variable.</entry>
		  <entry>
<programlisting width="36">
<![CDATA[
$ echo $mypath:e                    
c /usr/src/bar.cc
$ echo $mypath:ge
c cc
]]>
</programlisting>
</entry>
		</row>


		<row>
		  <!-- <entry><command>:q</command></entry> -->
		  <entrytbl cols="1">
		    <tbody>
		      <row>
			<entry><command>:q</command>&nbsp;&nbsp;
			       <command>:gq</command></entry>
		      </row>
		    </tbody>
		  </entrytbl>

		  <entry>quote la variable pour éviter tout mécanisme de substitution.</entry>

		  <entry></entry>
		</row>

		<row>
		  <!-- <entry><command>:x</command></entry> -->
		  <entrytbl cols="1">
		    <tbody>
		      <row>
			<entry><command>:x</command>&nbsp;&nbsp;
			       <command>:gx</command></entry>
		      </row>
		    </tbody>
		  </entrytbl>

		  <entrytbl cols="1">
		    <tbody>
		      <row>
			<entry align="left">idem précédent, mais cassure en mots sur les caractères : blanc,
 			                    espace et nouvelle ligne.</entry>
		      </row>
		    </tbody>
		  </entrytbl>
		  <entry></entry>
		</row>

	      </tbody>
	    </tgroup>
	  </table>

</para>
      </formalpara>


      <formalpara>
	<title>Mécanismes de substitution</title>
	<para>
        <table>
	    <title>Clé de substitution</title>
	    <tgroup cols="2">

	      <thead valign="middle">
		<row>
		  <entry align="center">Clé</entry>
		  <entry align="center">Sémantique</entry>
		</row>
	      </thead>

	      <tbody>	      	     	    		
		<row>
		  <entry><varname>$?&lt;name&gt;</varname> = <varname>${?&lt;name&gt;}</varname></entry>
		  <entry>Renvoit 1 si la variable est définie, 0 sinon.</entry>
		</row>

		<row>
		  <entry><varname>$?0</varname></entry>
		  <entry>Renvoit 1 si $0 est définie, 0 sinon.</entry>

		</row>

		<row>
		  <entry><varname>$$</varname></entry>
		  <entry>Substituée par le pid du &shell; parent.</entry>

		</row>
		
		<row>
		  <entry><varname>$!</varname></entry>
		  <entry>Substituée par le pid du dernier processus asynchrone lancé par le &shell; parent.</entry>

		</row>

		<row>
		  <entry><varname>$&lt;</varname></entry>
		  <entry>Substituée par une ligne de l'entrée standard.</entry>

		</row>
	      </tbody>
	    </tgroup>
	  </table>


<programlisting width="80">
<![CDATA[
$ set v = toto
$ echo ${?v}   # renvoit 1 puisque la variable v est définie        
1
$ echo $u
u: Undefined variable.
$ echo ${?u}   # moyen commode pour savoir si une variable est définie          
0 
]]>
</programlisting>
</para>
      </formalpara>


    </sect2>

    <sect2>
      <title>Paramètres du shell</title>
      <para>Le &shell; définit pour chaque commande un certain nombre de paramètres <quote>automatiques</quote>.

<table>
	  <title>Opérateurs de comparaison</title>
	  <tgroup cols="2">

	    <thead valign="middle">
	      <row>
		<entry align="center">Paramètre(s)</entry>
		<entry align="center">Utilisation</entry>
	      </row>
	    </thead>

	    <tbody>	      	     	    
	      <row>
		<entry align="left"><varname>$0</varname></entry>
		<entry align="justify">nom de la commande ou du script invoqué.</entry>
	      </row>

	      <row>
		<entry><varname>$1</varname>, <varname>$2</varname> .. <varname>$n</varname>&nbsp;&nbsp;
		      <varname>${1}</varname>, <varname>${2}</varname> .. <varname>${n}</varname></entry>
		<entry>encore équivalent à <varname>$argv[1]</varname>, <varname>$argv[2]</varname>, .. <varname>$argv[n]</varname> &nbsp;&nbsp;
valeurs des paramètres positionnels passés à la commande ou au script.</entry>
	      </row>

	      <row>
		<entry align="left"><varname>$*</varname> = <varname>$argv[*]</varname>
		      &nbsp;&nbsp;&nbsp; = <varname>${argv[*]}</varname></entry>
		<entry align="left">ensemble des paramètres, sauf $0.</entry>
	      </row>

	      <row>
		<entry><varname>$#</varname> = <varname>$#argv</varname>
		      &nbsp;&nbsp;&nbsp;&nbsp; = <varname>${#argv}</varname></entry>

		<entry colname="c2" align="left">nombre de paramètres effectifs, $0 non compris.</entry>
	      </row>	      	      
	    </tbody>
	  </tgroup>
	</table>

<programlisting width="80">
<emphasis>CODE :</emphasis>
<![CDATA[
#!/bin/csh
# ~/bin/testparm.sh

echo 'je suis le script, $0 = ' $0

if ( ${#argv} > 0 ) then
    echo ' évoqué avec $# (= $#argv = ${#argv}) = ' ${#argv}  ' arguments sur la
 ligne de commande'
    echo 'Voici les paramètres : $* (= $argv[*] = ${argv[*]}) = ' ${argv[*]}
    set i = 1
    foreach param ( $argv[*] ) 
        echo "paramètre ($i) :  $param"
        @ i++
    end
else
    echo ' pas d arguments, nb arg $# (= $#argv = ${#argv}) = ' ${#argv}
endif

# fin du script

]]>
<emphasis>EXEMPLE :</emphasis>
<![CDATA[
$ ./testparam.sh toto titi tutu 147
je suis le script, $0 =  ./testparam.sh
 évoqué avec $# (= $#argv = ${#argv}) =  4  arguments sur la ligne de commande  
Voici les paramètres : $* (= $argv[*]) =  toto titi tutu 147
paramètre (1) :  toto
paramètre (2) :  titi
paramètre (3) :  tutu
paramètre (4) :  147
$
$ ./testparam.sh
je suis le script, $0 =  ./testparam.sh
 pas d arguments, nb arg $# (= $#argv = ${#argv}) =  0
$
]]>
</programlisting>

</para>
    </sect2>

    <sect2>
      <title>Lecture sur l'entrée standard</title>
      <para>Elle se fait en utilisant la  variable spéciale <varname>$&lt;</varname>  

<programlisting width="80">
<emphasis>CODE :</emphasis>
<![CDATA[
#!/bin/csh
# ~/bin/testread.sh                                                             

echo -n " Votre réponse (o, n) ? "
set rep = $<

if ( $rep == o ) then 
   echo "réponse oui"
else
   echo autre réponse : $rep
endif
]]>

<emphasis>EXEMPLE :</emphasis>
<![CDATA[
$ ./testread.sh
Votre réponse (o, n) ? yes
autre réponse : yes

$ ./testread.sh
 Votre réponse (o, n) ? o
réponse oui
]]>
</programlisting>

</para>
    </sect2>


    <sect2>
      <title>Expressions conditionnelles</title>


      <para> <emphasis role="bold">Règles</emphasis> :
<itemizedlist>
	  <listitem><para>Les expressions utilisent les mêmes opérateurs que le langage <emphasis>C</emphasis> (sémantique identique. On retrouve les instructions <command>if</command>,  <command>while</command>, <command>@</command> et <command>exit</command>,</para></listitem>
	  <listitem><para>Les chaines numériques commençant par un 0 sont interprétées comme des valeurs en base octale,</para></listitem>
	  <listitem><para>Le résultat de toute expression est une chaîne représentant un nombre décimal.</para></listitem>
	  <listitem><para>La valeur 0 s'interprète en contexte logique comme la valeur <quote>faux</quote>, toutes les autres ont la valeur <quote>vrai</quote>.</para></listitem>
	</itemizedlist>

<table id="expr">
	  <title>Opérateurs de comparaison</title>
	  <!-- one of (graphic mediaobject tgroup) -->
	  <tgroup cols="2">

	    <thead valign="middle">
	      <row>
		<!-- one of (entrytbl entry) -->
		<entry align="center">Opérateur</entry>
		<entry align="center">Sémantique</entry>
	      </row>
	    </thead>

	    <tbody>

              <!-- FILE --> 
	      <row>
		<entry namest="c1" nameend="c2"><emphasis role="bold">O P E R A T E U R S &nbsp;&nbsp; D E &nbsp;&nbsp; F I C H I E R S</emphasis></entry>
	      </row>
	      	     	    
	      <row>
		<entry><command><option>-d</option> &lt;filename&gt;</command></entry>
		<entry>  est vraie si le fichier désigné par <emphasis>&lt;filename&gt;</emphasis> est un répertoire.</entry>
	      </row>

	      <row>
		<entry><command><option>-e</option> &lt;filename&gt;</command></entry>
		<entry>  est vraie si le fichier désigné par <emphasis>&lt;filename&gt;</emphasis> existe.</entry>
	      </row>

	      <row>
		<entry><command><option>-f</option> &lt;filename&gt;</command></entry>
		<entry>  est vraie si le fichier désigné par <emphasis>&lt;filename&gt;</emphasis> est un fichier régulier.</entry>
	      </row>
	      
	      <row>
		<entry><command><option>-o</option> &lt;filename&gt;</command></entry>
		<entry>  est vraie si le fichier désigné par <emphasis>&lt;filename&gt;</emphasis> est propriété de l'utilisateur.</entry>
	      </row>

	      <row>
		<entry><command><option>-r</option> &lt;filename&gt;</command></entry>
		<entry>  est vraie si le fichier désigné par <emphasis>&lt;filename&gt;</emphasis> est un fichier accessible en lecture.</entry>
	      </row>

	      <row>
		<entry><command><option>-w</option> &lt;filename&gt;</command></entry>
		<entry>  est vraie si le fichier désigné par <emphasis>&lt;filename&gt;</emphasis> est un fichier accessible en écriture.</entry>
	      </row>

	      <row>
		<entry><command><option>-x</option> &lt;filename&gt;</command></entry>
		<entry>  est vraie si le fichier désigné par <emphasis>&lt;filename&gt;</emphasis> est un fichier exécutable.</entry>
	      </row>

	      <row>
		<entry><command><option>-z</option> &lt;filename&gt;</command></entry>
		<entry>  est vraie si le fichier désigné par <emphasis>&lt;filename&gt;</emphasis> est de taille nulle.</entry>
	      </row>

	      <row>
		<entry><command><option>-b</option> &lt;filename&gt;</command></entry>
		<entry>[<emphasis role="bold">&fshell2;</emphasis>]   est vraie si le fichier désigné par <emphasis>&lt;filename&gt;</emphasis> est un fichier spécial en mode bloc.</entry>
	      </row>
              

	        <row>
		<entry><command><option>-c</option> &lt;filename&gt;</command></entry>
		<entry>[<emphasis role="bold">&fshell2;</emphasis>]   est vraie si le fichier désigné par <emphasis>&lt;filename&gt;</emphasis> est un fichier spécial en mode caractère.</entry>
	      </row>

	      <row>
		<entry><command><option>-l</option> &lt;filename&gt;</command></entry>
		<entry>[<emphasis role="bold">&fshell2;</emphasis>]   est vraie si le fichier désigné par <emphasis>&lt;filename&gt;</emphasis> est un lien symbolique.</entry>
	      </row>

	      <row>
		<entry><command><option>-p</option> &lt;filename&gt;</command></entry>
		<entry>[<emphasis role="bold">&fshell2;</emphasis>]   est vraie si le fichier désigné par <emphasis>&lt;filename&gt;</emphasis> est un <emphasis>tube nommés</emphasis> (<emphasis>FIFO</emphasis>).</entry>
	      </row>

	      <row>
		<entry><command><option>-S</option> &lt;filename&gt;</command></entry>
		<entry>[<emphasis role="bold">&fshell2;</emphasis>]  est vraie si le fichier désigné par <emphasis>&lt;filename&gt;</emphasis> est un <emphasis>socket</emphasis>.</entry>
	      </row>


              <!-- STRING --> 
	      <row>
		<entry namest="c1" nameend="c2"><emphasis role="bold">C O M P A R A I S O N &nbsp;&nbsp; D E &nbsp;&nbsp; C H A I N E S</emphasis>
</entry>
	      </row>
		      
	      <row>
		<entry><command>&lt;str1&gt; <option>==</option> &lt;str2&gt;</command></entry>
		<entry>est vraie si <emphasis>&lt;str1&gt;</emphasis> est égale à <emphasis>&lt;str2&gt;</emphasis>.</entry>
	      </row>

	      <row>
		<entry><command>&lt;str1&gt; <option>!=</option> &lt;str2&gt;</command></entry>
		<entry>est vraie si <emphasis>&lt;str1&gt;</emphasis> est différente de <emphasis>&lt;str2&gt;</emphasis>.</entry>
	      </row>
              
	      <row>
		<entry><command>&lt;str1&gt; <option>=~</option> &lt;str2&gt;</command></entry>
		<entry>  est vraie si le motif <emphasis>&lt;str2&gt;</emphasis> (<foreignphrase>right hand side</foreignphrase>) correspond au motif <emphasis>&lt;str1&gt;</emphasis>.</entry>
	      </row>

	      <row>
		<entry><command>&lt;str1&gt; <option>!~</option> &lt;str2&gt;</command></entry>
		<entry>  est vraie si le motif <emphasis>&lt;str2&gt;</emphasis> (<foreignphrase>right hand side</foreignphrase>) ne correspond pas au motif <emphasis>&lt;str1&gt;</emphasis>.</entry>
	      </row>
	      
	      <!-- ENTIER --> 
	      <row>
		<entry namest="c1" nameend="c2"><emphasis role="bold">C O M P A R A I S O N &nbsp;&nbsp; D ' E N T I E R S</emphasis></entry>
	      </row>
	      
	      <row>
		<entry><command>&lt;int1&gt; <option>&gt;=</option> &lt;int2&gt;</command></entry>
		<entry>est vraie si <emphasis>&lt;int1&gt;</emphasis> est supérieur ou égal à <emphasis>&lt;int2&gt;</emphasis>.</entry>
	      </row>
	      
	       <row>
		<entry><command>&lt;int1&gt; <option>&gt;</option> &lt;int2&gt;</command></entry>
		<entry>est vraie si <emphasis>&lt;int1&gt;</emphasis> est strictement supérieur à <emphasis>&lt;int2&gt;</emphasis>.</entry>
	      </row>

	       <row>
		<entry><command>&lt;int1&gt; <option>&lt;=</option> &lt;int2&gt;</command></entry>
		<entry>est vraie si <emphasis>&lt;int1&gt;</emphasis> est inférieur ou égal à <emphasis>&lt;int2&gt;</emphasis>.</entry>
	      </row>

	      <row>
		<entry><command>&lt;int1&gt; <option>&lt;</option> &lt;int2&gt;</command></entry>
		<entry>est vraie si <emphasis>&lt;int1&gt;</emphasis> est strictement inférieur à <emphasis>&lt;int2&gt;</emphasis>.</entry>
	      </row>


	      <!-- COMBINAISON D'EXPR --> 
	      <row>
		<entry namest="c1" nameend="c2"><emphasis role="bold">C O M B I N A I S O N &nbsp;&nbsp; D ' E X P R E S S I O N S</emphasis></entry>
	      </row>
	      
	      <row>
		<entry><command> ( &lt;expr&gt; ) </command></entry>
		<entry>est vraie si <emphasis>&lt;expr&gt;</emphasis> est vraie.</entry>
	      </row>

	      <row>
		<entry><command> <option>!</option> &lt;expr&gt; </command></entry>
		<entry>est vraie si <emphasis>&lt;expr&gt;</emphasis> est fausse.</entry>
	      </row>

	      <row>
		<entry><command> &lt;expr1&gt; <option>&amp;&amp;</option> &lt;expr2&gt; </command></entry>
		<entry>est vraie si <emphasis>&lt;expr1&gt;</emphasis> et <emphasis>&lt;expr2&gt;</emphasis> sont simultanément vraies.</entry>
	      </row>
	      
	      <row>
		<entry><command> &lt;expr1&gt; <option>||</option> &lt;expr2&gt; </command></entry>
		<entry>est vraie si <emphasis>&lt;expr1&gt;</emphasis> ou <emphasis>&lt;expr2&gt;</emphasis> est/sont vraie(s).</entry>
	      </row>
	      

	    </tbody>
	  </tgroup>
	</table>


<table>
	  <title>Opérateurs (par ordre décroissant de priorité)</title>
	  <tgroup cols="2">


	    <thead valign="middle">
	      <row>
		<entry align="center">Opérateurs</entry>
		<entry align="center">Sémantique</entry>
	      </row>
	    </thead>

	    <tbody>	      	     	    
	      
	      <row>
		<entry><command>( &nbsp; )</command> </entry>
		<entry>regroupement</entry>
	      </row>

	      <row>
		<entry><command>~</command> </entry>
		<entry>complément bit à bit</entry>
	      </row>

	      <row>
		<entry><command>!</command> </entry>
		<entry>négation logique.</entry>
	      </row>

	      <row>
		<entry><command>*</command> &nbsp; <command>/</command> &nbsp; <command>%</command></entry>
		<entry>multiplication, division, modulo</entry>
	      </row>

     	      <row>
		<entry><command>+</command> &nbsp; <command>-</command></entry>
		<entry>addition, soustraction</entry>
	      </row>

	      <row>
		<entry><command>&lt;&lt;</command> &nbsp; <command>&gt;&gt;</command></entry>
		<entry>décalage à gauche, décalage à droite</entry>
	      </row>

	      <row>
		<entry><command>&lt;=</command> &nbsp; <command>&lt;</command> &nbsp; <command>&gt;=</command> &nbsp; <command>&gt;</command></entry>
		<entry>opérateurs relationnels</entry>
	      </row>

	      <row>
		<entry><command>==</command> &nbsp; <command>!=</command> &nbsp; <command>=~</command> &nbsp; <command>!~</command></entry>
		<entry>opérateurs de comparaisons de chaînes</entry>
	      </row>

	      <row>
		<entry><command>&amp;</command> </entry>
		<entry><quote>et</quote> bit à bit</entry>
	      </row>
	      
	      <row>
		<entry><command>^</command> </entry>
		<entry><quote>ou exclusif</quote> bit à bit</entry>
	      </row>
	      
	      <row>
		<entry><command>|</command> </entry>
		<entry><quote>ou</quote> (inclusif) bit à bit</entry>
	      </row>
	      	      
	      <row>
		<entry><command>&amp;&amp;</command> </entry>
		<entry><quote>et</quote> logique</entry>
	      </row>

	      <row>
		<entry><command>||</command> </entry>
		<entry><quote>ou</quote> logique</entry>
	      </row>
     	      
	    </tbody>
	  </tgroup>
	</table>

La commande interne <command>@</command> permet de réaliser des opérations arithmétiques sur des valeurs ou variables entières, attention à respecter l'espace entre le symbole @ et la variable.

<programlisting width="80">
<![CDATA[
$ set v = 3
$ set u = 8
$ set p = 5
$ @ x = $v + $u * $p   # attention à la priorité des opérateurs                 
$ echo $x
43
$ @ x = ( $v + $u ) * $p
55

$ @ q = $u / $p        # division entière
$ @ r = $u % $p
$ echo quotient = $q et reste = $r
quotient = 1 et reste = 3

$ @ v++                # incrémentation d'une unité
$ echo $v
4

$ @ v += 2             # incrémentation de deux unités
$ echo $v
6

$ @ u /= 2             # @ u = u / 2
$ echo $u
4

$ @ u = ( $u <<  3 )   # décalage à gauche de 3 bits, ce qui revient à une x 8  
$ echo $u
32

$ @ v = (( $v + 4 ) >> 2 ) # 10 décaler de 2 bits à droite, soit 10 / 4 = 2
$ echo $v
2

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

    
    
</sect1>





<!-- 4e partie -->
  <sect1>
    <title> Les apports de TCsh</title>

    <sect2>
      <title><foreignphrase>Completion</foreignphrase> étendue</title>
      <para>Sous &fshell2; le mécanisme de <foreignphrase>completion</foreignphrase> des noms a été amélioré. Ce &shell; peut compléter les noms des fichiers, des commandes et des variables. De plus la <foreignphrase>completion</foreignphrase> des noms de fichiers est programmable !</para>

      <para>La <foreignphrase>completion</foreignphrase> est déclenchable par la touche &lt;<command>TAB</command>&gt;, bien que par compatibilité ascendante avec <command>&fshell;</command>, la touche &lt;<command>ESC</command>&gt; reste opérationnelle.</para>
    
      <formalpara>
	<title>Contexte de variables :</title>
	<para>Il faut utiliser le préfixe <command>$</command> (il change le contexte de la <foreignphrase>completion</foreignphrase>) :
<programlisting width="80">
<![CDATA[
$ set varia_1=10                                                                
$ echo $var<TAB>
$ echo $varia_1 <ENTREE>
10
]]>
</programlisting>
</para>
      </formalpara>
      
<!-- 
    <para> &todo; </para>
-->
    </sect2>


    <sect2>      
      <title><command>bindkey</command></title>
      <para> Cette commande permet l'édition des commandes en ligne dans un buffer au moyen des contrôles associés aux éditeurs classiques d'&Unix;, à savoir <command>vi</command> ou <command>emacs</command>. Utilisée seule, elle retourne la liste des associations clés/commandes. </para>

<para>Le positionnement par défaut est souvent le mode <command>emacs</command>, il est déterminé à la compilation. La variable <command>version</command> permet de connaître la version de la commande ainsi que les options de compilation. Dans l'exemple suivant, l'absence de la clé <command>vi</command>, permet d'affirmer que le mode par défaut est <command>emacs</command>.
<programlisting width="80">
<![CDATA[
$ echo $version
tcsh 6.12.00 (Astron) 2002-07-23 (i386-intel-FreeBSD) options 8b,nls,dl,al,kan,s
m,rh,color,dspm,filec
]]>
</programlisting>
</para>

<para>Cette commande permet aussi de commuter entre le mode <command>vi</command> et le mode <command>emacs</command>.
<programlisting width="80">
<![CDATA[
$ bindkey -e   # mode emacs                                                     
$ bindkey -v   # mode vi
]]>
</programlisting>
</para>

<para>
Dans le tableau suivant, nous présentons un sous-ensemble des commandes d'édition :
<table>
	  <title> Quelques couples clé/commande en mode <command>emacs</command></title>
	  <!-- one of (graphic mediaobject tgroup) -->
	  <tgroup cols="2" align='left'>
          
	    <thead>
	      <row>
		<!-- one of (entrytbl entry) -->
		<entry align='center'> Clé </entry>
		<entry align='center'> Commande </entry>
	      </row>
	    </thead>
	  <tbody>
	    <row>
	      <!-- one of (entrytbl entry) -->
		<entry align='center'>^A</entry>
		<entry>Positionne le curseur en début de ligne</entry>
	      </row>
	      <row>
		<entry align='center'>^B</entry>
		<entry>Recule horizontalement le curseur d'un caractère</entry>
	      </row>
 	      <row>
		<entry align='center'>^E</entry>
		<entry>Postionne le curseur en fin de ligne</entry>
	      </row>
	      <row>
		<entry align='center'>^L</entry>
		<entry>Efface l'ecran</entry>
	      </row>
	      
	      <row>
		<entry align='center'>^K</entry>
		<entry>Coupe tous les caractères à la droite du curseur</entry>
	      </row>

	      <row>
		<entry align='center'>^T</entry>
		<entry>Transposition de caractères</entry>
	      </row>

	      <row>
		<entry align='center' >^M</entry>
		<entry>Nouvelle ligne</entry>
	      </row>
	     
	      <row>
		<entry align='center'>^U</entry>
		<entry>Efface toute la ligne</entry>
	      </row>	      
	      	      
	      <row>
		<entry align='center'>^C</entry>
		<entry>Signal d'interruption</entry>
	      </row>
	      
	      <row>
		<entry align='center'>^Z</entry>
		<entry>Signal de suspension</entry>
	      </row>
	 
	      <row>
		<entry align='center'>Backspace</entry>
		<entry>Efface le premier caractère situé à gauche du curseur</entry>
	      </row>
	      <row>
		<entry align='center'>Flèche gauche</entry>
		<entry>Déplacement d'un caractère à gauche du curseur</entry>
	      </row>
	      <row>
		<entry align='center'>Flèche droite</entry>
		<entry>Déplacement d'un caractère situé à droite du curseur</entry>
	      </row>
	      <row>
		<entry align='center'>Flèche haut</entry>
		<entry>Remonte dans l'historique des commandes (vers les commandes les plus anciennes) </entry>
	      </row>	      
	      <row>
		<entry align='center'>Flèche bas</entry>
		<entry>Descend dans l'historique des commandes</entry>
	      </row>
	    </tbody>
	  </tgroup>
	</table>

</para>
</sect2>
    
    <sect2>
      <title><foreignphrase>Spelling Correction</foreignphrase></title>
      <para> Ce mécanisme est déclenché en postionnant la variable (interne) &fshell2; <varname>correct</varname> (valeurs possibles <emphasis>cmd</emphasis> ou <emphasis>all</emphasis>) :   

<programlisting width="80">
<![CDATA[
$ set correct = cmd
$ lzss test.csh                          # ooops typo !

CORRECT>less test.csh  (y|n|e|a)? yes    # frappe de la touche y ou <ESPACE>    
#!/bin/csh                               # lecture et affichage du fichier

echo '\nJe suis le programme $0   : ' $0
...
]]>
</programlisting>
</para>
    </sect2>

  </sect1>






<!-- VERSION ASR DEBUT --> 

<!-- 4e PARTIE : EXOS -->

  <sect1>
    <title>Exercices</title>

    <simplesect>
      <title>Exercice - Mécanisme d'évaluation (1) </title>
      <para> Soit les affectations suivantes :

<programlisting width="80">
<![CDATA[
$ set x=date                                                                        
$ set y=foobar 
]]>
</programlisting>
</para>

      
      <para>Tester les commandes suivantes et expliquer dans chaque cas le résultat obtenu.
<programlisting width="80">
<![CDATA[
$ echo $x ; echo $y ; echo $z                                                   

$ echo "$x" ; echo "$y" ; echo "$z"

$ echo '$x' ; echo '$y' ; echo '$z'

$ echo `$x` ; echo `$y` ; echo `$z` 

$ $x ; $y ; $z

$ "$x" ; "$y" ; "$z"

$ '$x' ; '$y' ; '$z'

$ `$x` ;  `$y` ; `$z` 

$ $y=`$x` 

$ echo $foobar
]]>
</programlisting>
</para>
    </simplesect>

    <simplesect>
      <title>Exercice - Mécanisme d'évaluation (2)</title>
            
      <para>Tester les commandes suivantes et expliquer dans chaque cas le résultat obtenu.
<programlisting width="80">
<![CDATA[
$ echo pwd                                                                      

$ `echo pwd`

$ 'echo pwd'

$ "echo pwd"

$ echo echo pwd

$ echo `echo pwd`

$ echo 'echo pwd'

$ echo "echo pwd"

$ echo '`echo pwd`'

$ echo '`echo pwd`'
]]>
</programlisting>
</para>
    </simplesect>


        <simplesect>
      <title>Exercice - Modification de l'environnement d'un processus, incidence sur le/les fils</title>
            
      <para>Dans un terminal, sous le &shell; courant définir deux variables (<varname>var1</varname> et <varname>var2</varname>) et modifier quelques variables d'environnement. Afficher l'environnement ainsi modifié.</para>

      <para>Dans ce même terminal, empiler un nouveau shell (<command>/bin/tcsh</command>). Quelle sont les valeurs de <varname>var1</varname> et <varname>var2</varname>, des variables d'environnement ?
Définir une variable <varname>var3</varname>.</para>

<para>Quitter ce &shell; et revenir à l'environnement initial (<command>exit</command>). Examiner son environnement, que vaut <varname>var3</varname> ? Conclure.</para>
      <para>Exporter maintenant la variable  <varname>var1</varname>, empiler un nouveau &shell;. Examiner son environnment. Modifier ensuite 
<varname>var1</varname>. Définir la variable <varname>var2</varname>. Quitter ce &shell;, pour revenir à celui de départ. Quelles sont les valeurs de  <varname>var1</varname> et <varname>var2</varname> ?</para>

      <para>Et si avant de quitter ce &shell; empilé, vous aviez exporté la variable <varname>var2</varname>, qu'auriez-vous obtenu ? </para>
    </simplesect>

    <simplesect>
      <title>Exercice - Exécution asynchrone concurrente de processus</title>
      <para>Exécuter la commande suivante dans un premier terminal, et dans un second ouvert pour l'occasion, lister les processus en cours d'exécution (se limiter aux seuls processus du terminal <quote>générateur</quote>), observer leur filiation, le nombre de processus : 
<programlisting width="80">
<![CDATA[
$ ( ls -la /usr/bin/ ; sleep 5 ; echo "5 - OK" ; last ) & \                     
( cat /etc/passwd ; sleep 7 ; echo "7 - OK" ; cat /etc/group ) & ps aux
]]>
</programlisting>
Observer l'entrelacement des résulats de ces commandes.
</para>
      <para>La séquence <foreignphrase>backslash</foreignphrase> (&ie; \), suivit de la touche &lt;Entrée&gt; indique au &shell; une continuation de la commande sur la ligne suivante. Que fait la commande <command>sleep</command> ?</para>
    </simplesect>
    

    <simplesect>
      <title>Exercice - Manipulation de jobs (1)</title>
      <para>Lancer la commande suivante : <computeroutput>find / -type d -print</computeroutput>, laquelle recherche tous les objets de type répertoire dans toute l'arborescence. La recherche se fait de manière récursive et comme l'arborescence est grande, l'exécution est <emphasis>un peu longue</emphasis>. On est bloqué tant que le processus exécutant le <command>find</command> n'est pas terminé. Il vous est demandé de :

<orderedlist numeration="lowerroman" spacing="compact">
	  <listitem>
	    <para>suspendre (ou stopper) le processus.</para>
	  </listitem>

	  <listitem>
	    <para>de le relancer en arrière-plan</para>
	  </listitem>

	  <listitem>
	    <para>de le ramener au premier plan</para>
	  </listitem>

	  <listitem>
	    <para>de le terminer.</para>
	  </listitem>
	</orderedlist>
Est-il possible de <quote>tuer</quote> des processus ne vous appartenant pas ? Tester-le.
</para>

<para>Si vous n'êtes pas assez rapide ou bien si la commande s'exécute trop rapidement, ouvrir un nouveau terminal et refaire le travail demandé. </para>

    </simplesect>


    <simplesect>
      <title>Exercice - Manipulation de jobs (2) </title>
      <para>Reprendre l'exemple de la commande <command>find</command>, de la section <quote><xref linkend="sect_redirection_comm"/></quote>, mais limiter la recherche au répertoire <filename>/etc</filename>.
<orderedlist numeration="lowerroman" spacing="compact">
	  <listitem>
	    <para>Rediriger uniquement la sortie d'erreur dans le fichier (<filename>ferr</filename>) ; </para>
	  </listitem>

	  <listitem>
	    <para>Rediriger uniquement la sortie standard dans un fichier (<filename>fout</filename>) ; </para>
	  </listitem>

	  <listitem>
	    <para>Multiplexer les sorties standard et d'erreur dans le même fichier (<filename>fouterr</filename>) ; </para>
	  </listitem>

	  <listitem>
	    <para>Rediriger (démultiplexer) la sortie standard et la sortie d'erreur dans les fichiers respectifs (<filename>fout</filename> et <filename>ferr</filename>).</para>
	  </listitem>

	</orderedlist>
</para>
    </simplesect>

  </sect1>
<sect1><title>Evaluation</title>
<para>Reprenez l'exercice sur les noms de domaines. 

<orderedlist>
	<listitem>
	<para>Automatisez tous les traitements à l'aide d'un script csh.</para></listitem>
	<listitem>
	<para>Ajoutez les fonctionnalités suivantes :
            <itemizedlist>
              <listitem>
               <para>Le fichier à traiter est un fichier à télécharger sur Internet. L'utilisateur donne l'URL du fichier.</para></listitem>
               <listitem>
               <para>Possibilité de donner plusieurs URLs. Les traitements aboutissent sur seulement 2 fichiers : un avec les adresses IP et l'autre avec les noms de domaines. </para></listitem>
            </itemizedlist>
        </para></listitem></orderedlist>
</para>
</sect1>
<!-- VERSION ASR FIN --> 





<!-- =================================================================== -->




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

     <bibliodiv> 
      
      <biblioentry>
	<abbrev>0</abbrev>
	<author>
	    <surname>OpenBSD man pages</surname>
	</author>
	<title> csh </title> 
 	<edition> 
 	 <ulink url="http://www.openbsd.org/cgi-bin/man.cgi">man csh</ulink>
	</edition> 
 	<date>Janvier 1994</date>
      </biblioentry>


       <biblioentry> 
 	<abbrev>1</abbrev> 
 	<author> 
 	  <firstname>Heuer</firstname> 
 	  <surname>Konrad</surname> 
 	</author> 
 	<title>Making friends with C-Shell and TC-shell, Part I </title> 
 	<edition> 
 	 <ulink url="http://ezine.daemonnews.org/200112/"></ulink>
	</edition> 
 	<date>Décembre 2001</date> 
       </biblioentry> 

      <biblioentry> 
 	<abbrev>2</abbrev> 
 	<author> 
 	  <firstname>Heuer</firstname> 
 	  <surname>Konrad</surname> 
 	</author> 
 	<title>Making friends with C-Shell and TC-shell, Part II </title> 
	<edition> 
 	 <ulink url="http://ezine.daemonnews.org/200201/"></ulink> 
	</edition> 
 	<date>Janvier 2002</date> 
       </biblioentry> 

      <biblioentry> 
 	<abbrev>3</abbrev> 
 	<author> 
 	  <firstname>Heuer</firstname> 
 	  <surname>Konrad</surname> 
 	</author> 
 	<title>Making friends with C-Shell and TC-shell, Part III </title> 
	<edition> 
 	 <ulink url="http://ezine.daemonnews.org/200202/"></ulink> 
 	</edition> 
 	<date>Février 2002 </date> 
       </biblioentry> 

      <biblioentry>
	<abbrev>4</abbrev>
	<author>
	    <surname>University of Hawaii at Manoa - College of Engineering</surname>
	</author>
	<title>The C Shell tutorial</title> 
 	<edition> 
 	 <ulink url="http://www.eng.hawaii.edu/Tutor/csh.html">csh tutorial</ulink>
	</edition> 
 	<date>2001</date>
      </biblioentry>

       <biblioentry> 
 	<abbrev>5</abbrev>
 	<author> 
 	  <firstname>Pélissier</firstname> 
 	  <surname>Christian</surname> 
 	</author> 
 	<title>Unix</title>	
	<subtitle>Utilisation, Administration, Réseau Internet</subtitle>
	<pagenums>Chap 9, pp 163-176</pagenums>
 	<edition> 
 	  HERMES
 	</edition> 
 	<date>1992, 1995, 1996, 1998</date>
	<isbn>isdn : 2-86601-707-2</isbn>
       </biblioentry> 
      

     </bibliodiv> 
   </bibliography> 
</article>


