<chapter id="chap_10">
<title>Un peu plus sur les variables</title>
<abstract>

<para>Dans ce chapitre, nous aborderons l'emploi plus poussé des variables et paramètres.  Une fois achevé, vous serez capable de&nbsp;:</para>
<para>
<itemizedlist>
<listitem><para>Déclarer et utiliser un tableau de variables</para></listitem>
<listitem><para>Spécifier le type de variable que vous voulez utiliser</para></listitem>
<listitem><para>Rendre les variables en lecture seule</para></listitem>
<listitem><para>Employer <command>set</command> pour affecter une valeur à une variable</para></listitem>
</itemizedlist>
</para>
</abstract>

<sect1 id="sect_10_01"><title>Types de variables</title>
<sect2 id="sect_10_01_01"><title>Affectation générale de valeur.</title>
<para>Comme nous l'avons déjà vu, Bash comprend plusieurs types de variables ou paramètres.  Jusqu'à maintenant, nous ne nous sommes pas inquiété du type de variable affectée, de sorte que nos variables pouvaient stocker toute sorte de valeur que nous leur affections. Une simple ligne de commande illustre ceci&nbsp;:</para>
<screen>
<prompt>[bob in ~]</prompt> <command><varname>VARIABLE</varname>=<parameter>12</parameter></command>

<prompt>[bob in ~]</prompt> <command>echo <varname>$VARIABLE</varname></command>
12

<prompt>[bob in ~]</prompt> <command><varname>VARIABLE</varname>=<parameter>string</parameter></command>

<prompt>[bob in ~]</prompt> <command>echo <varname>$VARIABLE</varname></command>
string
</screen>
<para>Il y a des cas où vous voulez éviter ce genre de comportement, par exemple quand vous manipulez des numéros de téléphone et autres codifications.  A part les entiers et les variables, vous pourriez aussi vouloir spécifier une variable avec une valeur constante.  Ceci est souvent fait au début du script, quand la valeur de la constante est définie.  Ensuite, il est seulement fait référence au nom de la variable stockant la constante, de sorte que quand la logique veut que la constante soit changée, cela n'est fait qu'à un endroit.  Une variable peut aussi être une série de variables de tout type, c'est à dire un  <emphasis>tableau</emphasis> de variables<indexterm><primary>arrays</primary><secondary>variables</secondary></indexterm> (<varname>VAR0</varname><varname>VAR1</varname>, <varname>VAR2</varname>, ... <varname>VARN</varname>).</para>
</sect2>
<sect2 id="sect_10_01_02"><title>Utiliser l'intégrée declare</title>
<para>Avec l'instruction <command>declare</command> nous pouvons encadrer l'affectation de valeur à une variable.</para>
<para>La syntaxe de <command>declare</command> est la suivante&nbsp;:</para>
<cmdsynopsis><command>declare <option>OPTION(s)</option> <varname>VARIABLE</varname>=value</command></cmdsynopsis>
<para>Les options suivantes sont employées pour déterminer le type de donnée de la variable et pour lui assigner des attributs&nbsp;:</para>

<table id="tab_10_01" frame="all"><title>Options de l'intégrée declare</title>
<tgroup cols="2" align="left" colsep="1" rowsep="1">
<thead>
<row><entry>Option</entry><entry>sens</entry></row>
</thead>
<tbody>
<row><entry><option>-a</option></entry><entry>Variable tableau<indexterm><primary>arrays</primary><secondary>declaration</secondary></indexterm>.</entry></row>
<row><entry><option>-f</option></entry><entry>Utilise uniquement les noms de fonction</entry></row>
<row><entry><option>-i</option></entry><entry>La variable doit être considérée en tant qu'entier, une évaluation<indexterm><primary>arithmetic evaluation</primary><secondary>declare built-in</secondary></indexterm> arithmétique est effectuée quand une valeur est assignée à la variable (voir <xref linkend="sect_03_04_05" />).</entry></row>
<row><entry><option>-p</option></entry><entry>Affiche les attributs et la valeur de chaque variable.  Quand <option>-p</option> est employé, les options supplémentaires sont ignorées.</entry></row>
<row><entry><option>-r</option></entry><entry>fait que la variable est en lecture seule.  A cette variable ne peut alors lui être affecté une autre valeur par une instruction ultérieure, de même qu'elle ne peut être supprimée.</entry></row>
<row><entry><option>-t</option></entry><entry>Donne à chaque variable l'attribut <emphasis>trace</emphasis>.</entry></row>
<row><entry><option>-x</option></entry><entry>Marque chaque variable comme exportée pour les commandes suivantes via l'environnement.</entry></row>
</tbody>
</tgroup>
</table>
<para>L'emploi de  <option>+</option> au lieu de <option>-</option> inhibe les attributs.  Quand c'est employé dans une fonction, <command>declare</command> créé des  variables locales.</para>
<para>L'exemple suivant montre comment l'assignation du type de variable influence la valeur.</para>
<screen>
<prompt>[bob in ~]</prompt> <command>declare <option>-i</option> <varname>VARIABLE</varname>=<parameter>12</parameter></command>

<prompt>[bob in ~]</prompt> <command><varname>VARIABLE</varname>=<parameter>string</parameter></command>

<prompt>[bob in ~]</prompt> <command>echo <varname>$VARIABLE</varname></command>
0

<prompt>[bob in ~]</prompt> <command>declare <option>-p</option> <varname>VARIABLE</varname></command>
declare -i VARIABLE="0"
</screen>
<para>Notez que Bash a une option pour déclarer une valeur numérique, mais aucune pour une valeur chaîne.  Ceci s'explique puisque, par défaut, si aucune spécification n'est indiquée, une variable peut stocker tout type de donnée&nbsp;:</para>
<screen>
<prompt>[bob in ~]</prompt> <command><varname>OTHERVAR</varname>=<parameter>blah</parameter></command>

<prompt>[bob in ~]</prompt> <command>declare <option>-p</option> <varname>OTHERVAR</varname></command>
declare -- OTHERVAR="blah"
</screen>
<para>Dès que vous restreignez l'affectation de valeurs à une variable, elle ne peut que contenir ce type de donnée.  Les restrictions possibles sont soit entier, constante, ou tableau.</para>
<para>Voir les pages info de Bash pour une aide sur le statut renvoyé.</para>
</sect2>
<sect2 id="sect_10_01_03"><title>Constantes</title>
<para>En Bash, les constantes sont créées en mettant en lecture seule une variable.  L'intégré <command>readonly</command> marque chaque variable spécifiée comme non modifiable..  La syntaxe est&nbsp;:</para>
<cmdsynopsis><command>readonly <option>OPTION</option> <varname>VARIABLE(s)</varname></command></cmdsynopsis>
<para>La valeur de ces variables ne peut plus être changée par une instruction ultérieure.  Si l'option <option>-f</option> est donnée, chaque variable réfère à une fonction Shell&nbsp;; voir <xref linkend="chap_11" />.  If <option>-a</option> est spécifié, chaque variable réfère à un tableau de variables.  Si aucun argument n'est donné, ou si <option>-p</option> est indiqué, une liste de toutes les variables en lecture est affichée.  Avec l'option <option>-p</option> le résultat peut être réutilisé comme entrée.</para>
<para>Le statut d'exécution est zéro, à moins qu'une option invalide ait été spécifiée, qu'une des variables ou fonctions n'existe pas, ou que <option>-f</option> ait été fourni en tant que nom de variable au lieu d'un nom de fonction.</para>
<screen>
<prompt>[bob in ~]</prompt> <command>readonly <varname>TUX</varname>=<parameter>penguinpower</parameter></command>

<prompt>[bob in ~]</prompt> <command><varname>TUX</varname>=<parameter>Mickeysoft</parameter></command>
bash: TUX: readonly variable
</screen>
</sect2>

</sect1>
<sect1 id="sect_10_02"><title>Variables tableau</title>
<sect2 id="sect_10_02_01"><title>Créer des tableaux</title>
<para>Un tableau est une variable contenant plusieurs valeurs.  Toute variable peut être utilisée comme étant un tableau<indexterm><primary>arrays</primary><secondary>declaration</secondary></indexterm>.  Il n'y a pas de limite maximum à la taille d'un tableau, ni de besoin que les éléments soient indexés ou assignés de façon contiguë.  Les tableaux démarrent à zéro&nbsp;: le premier élément est donc adressé avec le numéro 0.</para>
<para>Une déclaration indirecte peut se faire avec la syntaxe suivante de déclaration de variable&nbsp;:</para>
<cmdsynopsis><command><varname>ARRAY[INDEXNR]</varname>=value</command></cmdsynopsis>
<para>Le <emphasis>INDEXNR</emphasis> est traité comme une expression arithmétique qui doit être évalué comme nombre positif.</para>
<para>Une déclaration explicite d'un tableau est faite avec l'intégrée  <command>declare</command>&nbsp;:</para>
<cmdsynopsis><command>declare <option>-a</option> <varname>ARRAYNAME</varname></command></cmdsynopsis>
<para>Une déclaration avec un numéro d'index sera aussi acceptée, mais le numéro d'index sera ignoré.  Des attributs<indexterm><primary>arrays</primary><secondary>attributes</secondary></indexterm> du tableau peuvent être  spécifiés en employant les intégrées <command>declare</command> et <command>readonly</command>.  Les attributs s'appliquent à toutes les variables du tableau&nbsp;; vous ne pouvez avoir des tableaux mitigés.</para>
<para>Les variables de tableau peuvent aussi être créées avec une affectation composée selon ce format&nbsp;:</para>
<cmdsynopsis><command><varname>ARRAY</varname>=(value1 value2 ... valueN)</command></cmdsynopsis>
<para>Chaque valeur est alors de la forme <emphasis>[indexnumber=]string</emphasis>.  Le numéro d'index est optionnel.  Si il est fourni, l'index prend la valeur du numéro&nbsp;; sinon l'index de l'élément affecté est le numéro du dernier index assigné, plus un.  Le format est accepté par <command>declare</command> également.  Si aucun numéro d'index n'est fourni, l'indexation commence à zéro.</para>
<para>Ajouter un élément manquant ou suplémentaire à un tableau<indexterm><primary>arrays</primary><secondary>adding members</secondary></indexterm> se fait avec la syntaxe&nbsp;:</para>
<cmdsynopsis><command><varname>ARRAYNAME[indexnumber]</varname>=value</command></cmdsynopsis>
<para>Se rappeler que l'intégrée <command>read</command> possède l'option  <option>-a</option> qui autorise la lecture et l'affectation de valeurs des éléments d'un tableau.</para>
</sect2>
<sect2 id="sect_10_02_02"><title>Invoquer les variables d'un tableau</title>
<para>Afin de se référer au contenu d'un élément du tableau<indexterm><primary>arrays</primary><secondary>dereferencing</secondary></indexterm>, employer le symbole accolade.  C'est nécessaire, comme vous le voyez dans l'exemple suivant, pour échapper à l'interprétation du Shell des opérateurs d'expansion.  Si le numéro d'index est <emphasis>@</emphasis> ou <emphasis>*</emphasis>, tous les éléments du tableau sont considérés.</para>
<screen>
<prompt>[bob in ~]</prompt> <command><varname>ARRAY</varname>=<parameter>(one two three)</parameter></command>

<prompt>[bob in ~]</prompt> <command>echo <varname>${ARRAY[*]}</varname></command>
one two three

<prompt>[bob in ~]</prompt> <command>echo <varname>$ARRAY[*]</varname></command>
one[*]

<prompt>[bob in ~]</prompt> <command>echo <varname>${ARRAY[2]}</varname></command>
three

<prompt>[bob in ~]</prompt> <command><varname>ARRAY[3]</varname>=<parameter>four</parameter></command>

<prompt>[bob in ~]</prompt> <command>echo <varname>${ARRAY[*]}</varname></command>
one two three four
</screen>
<para>Se référer au contenu d'un élément de tableau sans indiquer le numéro d'index est équivalent à se référer au contenu du premier élément, celui d'index zéro.</para>
</sect2>
<sect2 id="sect_10_02_03"><title>Supprimer des variables tableau</title>
<para>L'intégrée <command>unset</command> est employée pour détruire un tableau <indexterm><primary>arrays</primary><secondary>unset</secondary></indexterm> ou des variables éléments du tableau&nbsp;:</para>
<screen>
<prompt>[bob in ~]</prompt> <command>unset <varname>ARRAY[1]</varname></command>

<prompt>[bob in ~]</prompt> <command>echo <varname>${ARRAY[*]}</varname></command>
one three four

<prompt>[bob in ~]</prompt> <command>unset <varname>ARRAY</varname></command>

<prompt>[bob in ~]</prompt> <command>echo <varname>${ARRAY[*]}</varname></command>
&lt;--no output--&gt;
</screen>
</sect2>
<sect2 id="sect_10_02_04"><title>Exemples de tableaux</title>
<para>Exemples pratiques de la manipulation de tableaux<indexterm><primary>arrays</primary><secondary>examples</secondary></indexterm> sont difficiles à trouver.  Vous trouverez plein de scripts qui ne font pas autre chose sur votre système que de calculer des séries mathématiques avec des tableaux, par exemple.  Et ça devrait être l'un des exemples les plus intéressants...la plupart des scripts ne font que montrer d'une façon hyper simplifiée et théorique ce que vous pouvez faire avec les tableaux.</para>
<para>La raison de cette fadeur tient en ce que les tableaux sont des structures plutôt complexes.  Vous verrez que les exemples les plus pratiques pour lesquels les tableaux peuvent être utilisés sont déjà mis en oeuvre sur votre système, mais à plus bas niveau, en langage C dans lequel la plupart des commandes UNIX sont écrites.  Un bon exemple est la commande intégrée Bash <command>history</command>.  Les lecteurs intéressés peuvent voir le répertoire <filename>built-ins</filename>  dans l'arbre des sources Bash et jeter un coup d'oeil à <filename>fc.def</filename>, qui est exécutée à la compilation des intégrées.</para>
<para>Une autre raison pour laquelle de bons exemples sont difficiles à trouver est que tous les Shell ne reconnaissent pas les tableaux, ce qui gêne la compatibilité.</para>
<para>Après des jours de recherche, j'ai finalement trouvé cet exemple qui s'exécute chez un fournisseur INTERNET.  Il distribue des fichiers de configuration de serveur WEB Apache sur des hôtes dans une ferme WEB&nbsp;:</para>
<screen>
#!/bin/bash

if [ $(whoami) != 'root' ]; then
        echo "Must be root to run $0"
        exit 1;
fi
if [ -z $1 ]; then
        echo "Utilisation : $0 &lt;/path/to/httpd.conf&gt;"
        exit 1
fi

httpd_conf_new=$1
httpd_conf_path="/usr/local/apache/conf"
login=htuser

farm_hosts=(web03 web04 web05 web06 web07)

for i in ${farm_hosts[@]}; do
        su $login -c "scp $httpd_conf_new ${i}:${httpd_conf_path}"
        su $login -c "ssh $i sudo /usr/local/apache/bin/apachectl graceful"

done
exit 0
</screen>
<para>D'abord 2 tests sont effectués pour contrôler que l'utilisateur idoïne fait s'exécuter ce script avec les paramètres ad hoc<indexterm><primary>arguments</primary><secondary>test example</secondary></indexterm>.  Les noms des hôtes qui doivent être configurés sont listés dans le tableau  <varname>farm_hosts</varname>.  Puis tous ces hôtes sont chargés avec le fichier de configuration Apache, après quoi le démon est redémarré.  Notez l'emploi de commandes de la suite Secure Shell, qui encryptent les connections aux hôtes distants.</para>
<para>Merci, Eugène et ses collègues, pour cette contribution.</para>
<para>Dan Richter a fourni l'exemple suivant.  Voici le problème auquel il était confronté&nbsp;:</para>
<para><quote>...Dans mon entreprise, nous avons des démonstrations sur notre site WEB, et chaque semaine quelqu'un est chargé de les tester toutes. Donc j'ai un travail cron qui remplit un tableau avec les candidats possibles, qui utilise <command>date <option>+%W</option></command> pour déterminer la semaine dans l'année, et fait une opération modulo pour trouver le bon index. La personne gâtée reçoit un courriel.</quote></para>
<para>Et voici la solution&nbsp;:</para>
<screen>
#!/bin/bash
# Ceci est le script : get-tester-address.sh 
#
# D'abord nous testons si Bash admet les tableaux..
# (Les tableaux ont été ajoutés récemment.)
#
whotest[0]='test' || (echo 'Echec : les tableaux ne sont pas admis dans cette version de Bash.' &amp;&amp; exit 2)
                                                                                
#
# Our list of candidates. (Vous êtes libre d'ajouter
# ou d'enlever des candidats.)
#
wholist=(
     'Bob Smith &lt;bob@example.com&gt;'
     'Jane L. Williams &lt;jane@example.com&gt;'
     'Eric S. Raymond &lt;esr@example.com&gt;'
     'Larry Wall &lt;wall@example.com&gt;'
     'Linus Torvalds &lt;linus@example.com&gt;'
   )
#
# Compte le nombre de testeurs candidats.
# (Boucle jusqu'à trouver une chaîne vide.)
#
count=0
while [ "x${wholist[count]}" != "x" ]
do
   count=$(( $count + 1 ))
done
                                                                                
#
# Maintenant nous calculons à qui c'est le tour.
#
week=`date '+%W'`       # La semaine dans l'année (0..53).
week=${week#0}          # Elimine de possible zéro au début.
                                                                                
let "index = $week % $count"   # week modulo count = la personne gâtée

email=${wholist[index]}     # Récupérer l'adresse email de cette personne.
                                                                                
echo $email             # Affiche l'adresse email.
</screen>
<para>Ce script est alors appelé dans d'autres scripts, tel que celui-ci, qui utilise un document <emphasis>intégré</emphasis>&nbsp;:</para>
<screen>
email=`get-tester-address.sh`   # Trouver à qui envoyer le courriel.
hostname=`hostname`             # Le nom de la machine locale.
                                                                                
#
# Envoyer le courriel à la bonne personne.
#
mail $email -s '[Demo Testing]' &lt;&lt;EOF
La personne gâtée de la semaine est : $email
                                                                                
Rappel : la liste de démonstrations est ici :
    http://web.example.com:8080/DemoSites
                                                                                
(Ce courriel a été généré par $0 depuis ${hostname}.)
EOF
</screen>
</sect2>

</sect1>
<sect1 id="sect_10_03"><title>Opérations sur les variables</title>
<sect2 id="sect_10_03_01"><title>Arithmétique sur les variables</title>
<para>Nous avons déjà abordé la question à la <xref linkend="sect_03_04_05" />.</para>
</sect2>
<sect2 id="sect_10_03_02"><title>Longueur de variable</title>
<para>La syntaxe <command>${#<varname>VAR</varname>}</command> calcul le nombre de caractères d'une variable.  Si <varname>VAR</varname> vaut <quote>*</quote> ou <quote>@</quote>, cette valeur est remplacée par le nombre de paramètres positionnels ou le nombre d'éléments dans le tableau<indexterm><primary>arrays</primary><secondary>number of elements</secondary></indexterm> en général.  En voici une démonstration ci-dessous&nbsp;:</para>
<screen>
<prompt>[bob in ~]</prompt> <command>echo <varname>$SHELL</varname></command>
/bin/bash

<prompt>[bob in ~]</prompt> <command>echo <varname>${#SHELL}</varname></command>
9

<prompt>[bob in ~]</prompt> <command><varname>ARRAY</varname>=<parameter>(one two three)</parameter></command>

<prompt>[bob in ~]</prompt> <command>echo <varname>${#ARRAY}</varname></command>
3
</screen>
</sect2>
<sect2 id="sect_10_03_03"><title>Transformation de variables</title>
<sect3 id="sect_10_03_03_01"><title>Substitution</title>
<cmdsynopsis><command>${<varname>VAR</varname>:-<parameter>WORD</parameter>}</command></cmdsynopsis>
<para>Si <varname>VAR</varname> n'est pas défini ou est nul, l'expansion de  <parameter>WORD</parameter> est employée&nbsp;; sinon la valeur de <varname>VAR</varname> est remplacée&nbsp;:</para>
<screen>
<prompt>[bob in ~]</prompt> <command>echo <varname>${TEST:-test}</varname></command>
test

<prompt>[bob in ~]</prompt> <command>echo <varname>$TEST</varname></command>
 

<prompt>[bob in ~]</prompt> <command>export <varname>TEST</varname>=<parameter>a_string</parameter></command>

<prompt>[bob in ~]</prompt> <command>echo <varname>${TEST:-test}</varname></command>
a_string

<prompt>[bob in ~]</prompt> <command>echo <varname>${TEST2:-$TEST}</varname></command>
a_string
</screen>
<para>Cette forme est souvent employée dans les tests conditionnels, par exemple dans celui-ci&nbsp;:</para>
<screen>
<command><parameter>[ -z "${COLUMNS:-}" ]</parameter> &amp;&amp; <varname>COLUMNS</varname>=<parameter>80</parameter></command>
</screen>
<para>C'est une notation plus courte pour</para>
<screen>
<command>if <parameter>[ -z "${COLUMNS:-}" ]</parameter>; then
        <varname>COLUMNS</varname>=<parameter>80</parameter>
fi</command>
</screen>
<para>Voir la <xref linkend="sect_07_01_02_03" /> pour plus de détails au sujet de ce type de test de condition.</para>
<para>Si le tiret (-) est remplacé par le signe égal (=), la valeur est affectée au paramètre si il n'existe pas&nbsp;:</para>
<screen>
<prompt>[bob in ~]</prompt> <command>echo <varname>$TEST2</varname></command>


<prompt>[bob in ~]</prompt> <command>echo <varname>${TEST2:=$TEST}</varname></command>
a_string

<prompt>[bob in ~]</prompt> <command>echo <varname>$TEST2</varname></command>
a_string
</screen>
<para>La syntaxe suivante teste l'existence d'une variable.  Si elle n'est pas déclarée, l'expansion de <parameter>WORD</parameter> est affichée sur le standard de résultat et un Shell non-interactif se termine.  Une démonstration&nbsp;:</para>
<screen>
<prompt>[bob in ~]</prompt> <command>cat <filename>vartest.sh</filename></command>
#!/bin/bash
 
# Ce script teste si une variable est déclarée.  Si non,
# Il quitte en affichant un message.
 
echo ${TESTVAR:?"Il y a tellement encore que je voudrais faire..."}
echo "TESTVAR est déclarée, nous pouvons traiter."

<prompt>[bob in testdir]</prompt> <command>./vartest.sh</command>
./vartest.sh: line 6: TESTVAR: Il y a tellement encore que je voudrais faire...

<prompt>[bob in testdir]</prompt> <command>export <varname>TESTVAR</varname>=<parameter>present</parameter></command>

<prompt>[bob in testdir]</prompt> <command>./vartest.sh</command>
present
TESTVAR est déclarée, nous pouvons traiter.
</screen>
<para>Avec <quote>+</quote> au lieu du point d'exclamation la variable prend la valeur de l'expansion de <parameter>WORD</parameter>&nbsp;; si elle n'existe pas, rien ne se produit.</para>
</sect3>
<sect3 id="sect_10_03_03_02"><title>Suppression de sous-chaînes</title>
<para>Pour éliminer d'une variable un nombre de caractères égal à <parameter>OFFSET</parameter>, la syntaxe à employer est&nbsp;:</para>
<cmdsynopsis><command>${<varname>VAR</varname>:<parameter>OFFSET</parameter>:<parameter>LENGTH</parameter>}</command></cmdsynopsis>
<para>Le paramètre <parameter>LENGTH</parameter> définit combien de caractères garder, à partir du premier caractère après le décalage.  Si <parameter>LENGTH</parameter> est omis, le reste du contenu de la variable est conservé&nbsp;:</para>
<screen>
<prompt>[bob in ~]</prompt> <command>export <varname>STRING</varname>=<parameter>"thisisaverylongname"</parameter></command>

<prompt>[bob in ~]</prompt> <command>echo <varname>${STRING:4}</varname></command>
isaverylongname

<prompt>[bob in ~]</prompt> <command>echo <varname>${STRING:6:5}</varname></command>
avery
</screen>
<cmdsynopsis><command>${<varname>VAR</varname>#<parameter>WORD</parameter>}</command></cmdsynopsis>
<para> et </para>
<cmdsynopsis><command>${<varname>VAR</varname>##<parameter>WORD</parameter>}</command></cmdsynopsis>
<para>Cette syntaxe est employée pour éliminer les correspondances du patron donné par l'expansion de <parameter>WORD</parameter> de <varname>VAR</varname>.  <parameter>WORD</parameter> est interprété pour donner un patron tout comme dans l'expansion de nom de fichier.  Si le patron correspond au début du résultat d'expansion de  <varname>VAR</varname>, alors le résultat est la valeur de <varname>VAR</varname> réduit au plus court patron correspondant (<quote>#</quote>) ou le plus long (quand employé avec <quote>##</quote>).</para>
<para>Si <varname>VAR</varname> est <varname>*</varname> ou <varname>@</varname>, l'opération de suppression du patron est effectuée sur chaque paramètre positionnel, et l'expansion est la liste résultante.</para>
<para>Si <varname>VAR</varname> est une variable tableau indexée par <quote>*</quote> ou <quote>@</quote>, l'opération de substitution de patron est effectuée pour chaque élément du tableau<indexterm><primary>arrays</primary><secondary>remove patterns</secondary></indexterm> l'un après l'autre, et l'expansion est la liste résultante.  Ceci est montré dans l'exemple ci-dessous&nbsp;:</para>
<screen>
<prompt>[bob in ~]</prompt> <command>echo <varname>${ARRAY[*]}</varname></command>
one two one three one four

<prompt>[bob in ~]</prompt> <command>echo <varname>${ARRAY[*]#one}</varname></command>
two three four

<prompt>[bob in ~]</prompt> <command>echo <varname>${ARRAY[*]#t}</varname></command>
one wo one hree one four

<prompt>[bob in ~]</prompt> <command>echo <varname>${ARRAY[*]#t*}</varname></command>
one wo one hree one four

<prompt>[bob in ~]</prompt> <command>echo <varname>${ARRAY[*]##t*}</varname></command>
one one one four
</screen>
<para>L'effet opposé est obtenu avec <quote>%</quote> et <quote>%%</quote>, comme dans l'exemple suivant.  <parameter>WORD</parameter> devrait correspondre à une portion en fin de chaîne&nbsp;:</para>
<screen>
<prompt>[bob in ~]</prompt> <command>echo <varname>$STRING</varname></command>
thisisaverylongname

<prompt>[bob in ~]</prompt> <command>echo <varname>${STRING%name}</varname></command>
thisisaverylong
</screen>

</sect3>
<sect3 id="sect_10_03_03_03"><title>Remplacer des parties de noms de variables</title>
<para>Ceci  est fait avec la syntaxe suivante </para> 
<cmdsynopsis><command>${<varname>VAR</varname>/<parameter>PATRON</parameter>/<parameter>CHAINE</parameter>}</command></cmdsynopsis>
<para>ou l'option</para>
<cmdsynopsis><command>${<varname>VAR</varname>//<parameter>PATRON</parameter>/<parameter>CHAINE</parameter>}</command></cmdsynopsis>
<para>syntax.  La première forme remplace seulement la première correspondance, la seconde remplace toutes les occurrences de <parameter>PATRON</parameter> par <parameter>CHAINE</parameter>&nbsp;:</para>
<screen>
<prompt>[bob in ~]</prompt> <command>echo <varname>${STRING/name/string}</varname></command>
thisisaverylongstring
</screen>
<para>Vous trouverez plus de détails dans les pages info de Bash.</para>
</sect3>
</sect2>

</sect1>
<sect1 id="sect_10_04"><title>Résumé</title>
<para>Normalement, une variable peut stocker tout type de donnée, à moins qu'elles soient déclarées explicitement.  Les variables constantes sont déclarées avec la commande intégrée  <command>readonly</command>.</para>
<para>Un tableau stocke un ensemble de variables.  Si un type de donnée est déclaré, alors tous les éléments du tableau seront considérés comme contenant seulement ce type de donnée.</para>
<para>Les fonctionnalités du Bash permettent la substitution et la transformation de variables <quote>au vol</quote>.  Les opérations standards incluent le calcul de la longueur de la variable, l'arithmétique de variables, la substitution du contenu - ou d'une partie - d'une variable.</para>

</sect1>
<sect1 id="sect_10_05"><title>Exercices</title>
<para>Voici quelques casse-têtes&nbsp;:</para>


<orderedlist>
<listitem><para>Ecrire un script qui fait ce qui suit&nbsp;:</para>
<itemizedlist>
<listitem><para>Affiche le nom du script qui s'exécute.</para></listitem>
<listitem><para>Afficher le premier, le troisième et le dixième paramètre donné au script.</para></listitem>
<listitem><para>Afficher le nombre total de paramètres du script.</para></listitem>
<listitem><para>Si il y a plus de 3 paramètres positionnels, employez <command>shift</command> pour décaler toutes les valeurs de 3 places vers la gauche.</para></listitem>
<listitem><para>Afficher toutes les valeurs des paramètres restants.</para></listitem>
<listitem><para>Affiche le nombre de paramètres.</para></listitem>
</itemizedlist>
<para>Tester avec zéro, un, trois et plus de dix paramètres.</para>

</listitem>
<listitem><para>Ecrire un script qui installe un navigateur WEB simple (en mode texte), avec <command>wget</command> et <command>links <option>-dump</option></command> pour afficher les pages HTML à l'intention de l'usager.  L'usager a 3 choix&nbsp;: entrer une URL,entrer <keycap>b</keycap> pour boucler,  <keycap>q</keycap> pour quitter.  Les 10 dernières URL entrées par l'usager sont stockées dans un tableau, duquel l'usager peut récupérer une URL avec la fonctionnalité <emphasis>boucler</emphasis>.</para>
</listitem>
</orderedlist>

</sect1>
</chapter>