2005-06-03 15:56:21 +02:00
|
|
|
|
<?xml version="1.0" encoding="ISO-8859-1"?>
|
|
|
|
|
<!DOCTYPE html
|
|
|
|
|
PUBLIC "-//ENS/Tuteurs//DTD TML 1//EN"
|
|
|
|
|
"tuteurs://DTD/tml.dtd">
|
|
|
|
|
<html>
|
|
|
|
|
<head>
|
|
|
|
|
<title>Boucles</title>
|
|
|
|
|
</head>
|
|
|
|
|
<body>
|
|
|
|
|
|
|
|
|
|
<h1>Structures de contr<74>le</h1>
|
|
|
|
|
|
|
|
|
|
<p>
|
|
|
|
|
Une fois que vous avez compris qu'un script n'est rien d'autre qu'une
|
2007-07-17 12:01:59 +02:00
|
|
|
|
suite de commandes, vous avez fait un grand pas<61>; chaque script
|
|
|
|
|
consiste <20> poser des rails<6C>: l'utilisateur n'a plus qu'<27> les suivre
|
2005-09-08 01:00:03 +02:00
|
|
|
|
(si tout cela ne vous para<72>t pas <20>vident, consultez la page d'<a
|
|
|
|
|
href="script.html">initiation <20> la programmation en shell</a>).
|
2005-06-03 15:56:21 +02:00
|
|
|
|
</p>
|
|
|
|
|
|
2007-07-17 12:01:59 +02:00
|
|
|
|
<p>Toutefois, avoir pos<6F> les rails ne suffit pas toujours<72>: il peut
|
2005-06-03 15:56:21 +02:00
|
|
|
|
importer de disposer de m<>canismes d'aiguillage. Les boucles vous
|
|
|
|
|
permettront de r<>aliser ces m<>canismes d'aiguillage, qui donneront <20> vos
|
|
|
|
|
scripts souplesse et efficacit<69>. </p>
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
2007-07-17 12:01:59 +02:00
|
|
|
|
<h2>Examiner une condition<6F>: <code>if</code> et <code>case</code></h2>
|
2005-06-03 15:56:21 +02:00
|
|
|
|
|
|
|
|
|
<h3>La boucle <code>if</code></h3>
|
|
|
|
|
|
|
|
|
|
<h4>Description</h4>
|
|
|
|
|
|
|
|
|
|
<p>
|
|
|
|
|
Robert le jardinier programme un hachoir en shell, et veut en interdire
|
|
|
|
|
l'acc<63>s <20> tout autre utilisateur que lui-m<>me, afin de prot<6F>ger le petit
|
|
|
|
|
<EFBFBD>mile de ce dangereux instrument. Le programme <code>hachoir</code> se
|
2007-07-17 12:01:59 +02:00
|
|
|
|
pose la question suivante<74>: est-ce que <code>$USER</code> vaut
|
|
|
|
|
<EFBFBD><EFBFBD>Robert<EFBFBD><EFBFBD><EFBFBD>?
|
2005-06-03 15:56:21 +02:00
|
|
|
|
</p>
|
|
|
|
|
|
|
|
|
|
<ul>
|
2007-07-17 12:01:59 +02:00
|
|
|
|
<li> Si oui, alors le hachoir doit se mettre en marche<68>;</li>
|
2005-06-03 15:56:21 +02:00
|
|
|
|
<li> si non, alors le hachoir doit refuser de se mettre en
|
|
|
|
|
marche.</li>
|
|
|
|
|
</ul>
|
|
|
|
|
|
|
|
|
|
<p>
|
2007-07-17 12:01:59 +02:00
|
|
|
|
C'est pour les structures de type <20><>si... alors... ou sinon<6F><6E>,
|
2005-06-03 15:56:21 +02:00
|
|
|
|
la commande <code>if</code> a <20>t<EFBFBD> faite. Elle est constitu<74>e de cinq
|
2007-07-17 12:01:59 +02:00
|
|
|
|
termes, dont trois sont obligatoires<65>:</p>
|
2005-06-03 15:56:21 +02:00
|
|
|
|
|
|
|
|
|
<ol>
|
2007-07-17 12:01:59 +02:00
|
|
|
|
<li> <code>if</code> (si), qui marque la condition <20> remplir<69>;
|
2005-06-03 15:56:21 +02:00
|
|
|
|
</li>
|
|
|
|
|
<li> <code>then</code> (alors), qui marque les cons<6E>quences si la
|
2007-07-17 12:01:59 +02:00
|
|
|
|
condition est remplie<69>; </li>
|
2005-06-03 15:56:21 +02:00
|
|
|
|
<li> <code>elif</code> (contraction de <em>else if</em>, qui signifie
|
2007-07-17 12:01:59 +02:00
|
|
|
|
<EFBFBD><EFBFBD>sinon, si...<2E><>), qui est <em>facultatif</em> et marque une
|
|
|
|
|
condition alternative<76>;</li>
|
2005-06-03 15:56:21 +02:00
|
|
|
|
<li> <code>else</code> (sinon), qui est <em>facultatif</em> et marque le
|
2007-07-17 12:01:59 +02:00
|
|
|
|
comportement <20> adopter si la condition n'est pas remplie<69>; </li>
|
2005-06-03 15:56:21 +02:00
|
|
|
|
<li> <code>fi</code> (<code>if</code> <20> l'envers), qui marque la fin de
|
|
|
|
|
la boucle.</li>
|
|
|
|
|
</ol>
|
|
|
|
|
|
2007-07-17 12:01:59 +02:00
|
|
|
|
<p>On peut donc taper<65>:</p>
|
2005-06-03 15:56:21 +02:00
|
|
|
|
|
|
|
|
|
<pre>if <em>commande</em> ; then <em>commandes</em> ; else <em>commandes</em> ; fi</pre>
|
|
|
|
|
|
|
|
|
|
<p class="continue"> ou bien (car le point et virgule <20>quivaut <20> un saut
|
2007-07-17 12:01:59 +02:00
|
|
|
|
de ligne)<29>:</p>
|
2005-06-03 15:56:21 +02:00
|
|
|
|
|
|
|
|
|
<pre>if <em>condition</em>
|
|
|
|
|
then <em>commandes</em>
|
|
|
|
|
elif <em>condition</em>
|
|
|
|
|
then <em>commandes</em>
|
|
|
|
|
else <em>commandes</em>
|
|
|
|
|
fi</pre>
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
<h4>Exemples</h4>
|
|
|
|
|
|
|
|
|
|
<h5>Exemple 1</h5>
|
|
|
|
|
<p>
|
2007-07-17 12:01:59 +02:00
|
|
|
|
Par exemple, pour le hachoir de Robert le jardinier, on aura<72>:
|
2005-06-03 15:56:21 +02:00
|
|
|
|
</p>
|
|
|
|
|
|
|
|
|
|
<pre>
|
|
|
|
|
if test $USER = Robert
|
|
|
|
|
then echo "Le hachoir va se mettre en marche."
|
|
|
|
|
<em>mettre en marche le hachoir</em>
|
|
|
|
|
else echo "Quand tu seras grand, $USER."
|
|
|
|
|
echo "Et fais bien attention en traversant la rue."
|
|
|
|
|
fi</pre>
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
<h5>Observations</h5>
|
|
|
|
|
|
|
|
|
|
<p> Comme vous pouvez le constater, <strong><3E> la suite des commandes
|
|
|
|
|
<code>then</code> et <code>else</code>, vous pouvez mettre autant de
|
|
|
|
|
commandes que vous le voulez</strong>. Le shell ex<65>cute tout ce qu'il
|
|
|
|
|
trouve jusqu'<27> la prochaine instruction.</p>
|
|
|
|
|
|
|
|
|
|
<p> Par exemple, si la condition indiqu<71>e par <code>if</code> est
|
|
|
|
|
remplie, le shell va ex<65>cuter tout ce qui suit <code>then</code> jusqu'<27>
|
2007-07-17 12:01:59 +02:00
|
|
|
|
ce qu'il trouve l'une de ces instructions<6E>:</p>
|
2005-06-03 15:56:21 +02:00
|
|
|
|
|
|
|
|
|
<ul>
|
|
|
|
|
<li> <code>elif</code>,</li>
|
|
|
|
|
<li> <code>else</code> ou</li>
|
|
|
|
|
<li> <code>fi</code>.</li>
|
|
|
|
|
</ul>
|
|
|
|
|
|
|
|
|
|
<h5>Exemple 2</h5>
|
|
|
|
|
|
2007-07-17 12:01:59 +02:00
|
|
|
|
<p>Autre exemple<6C>:</p>
|
2005-06-03 15:56:21 +02:00
|
|
|
|
|
|
|
|
|
<pre>
|
|
|
|
|
#!/bin/sh
|
|
|
|
|
# Fichier "mon-pwd"
|
|
|
|
|
|
|
|
|
|
if test $PWD = $HOME
|
|
|
|
|
then echo "Vous <20>tes dans votre r<>pertoire d'accueil."
|
|
|
|
|
elif test $PWD = $HOME/bin
|
|
|
|
|
then echo "Vous <20>tes dans votre r<>pertoire d'ex<65>cutables."
|
|
|
|
|
elif test $PWD = $HOME/bin/solaris
|
|
|
|
|
then echo "Vous <20>tes dans votre r<>pertoire d'ex<65>cutables pour Solaris."
|
|
|
|
|
else echo 'Vous <20>tes dans un r<>pertoire quelconque, qui n'est ni $HOME,'
|
|
|
|
|
echo 'ni $HOME/bin, ni $HOME/bin/solaris. '"Vous <20>tes dans $PWD."
|
|
|
|
|
fi
|
|
|
|
|
</pre>
|
|
|
|
|
|
|
|
|
|
<h5>Observations</h5>
|
|
|
|
|
|
|
|
|
|
<ol>
|
|
|
|
|
<li> <strong>Le nombre de <code>elif</code> successifs est
|
|
|
|
|
illimit<EFBFBD></strong>, alors qu'il ne peut (et c'est logique) y avoir qu'une
|
|
|
|
|
seule condition <code>if</code>, une seule instruction <code>else</code>
|
|
|
|
|
et une seule instruction <code>fi</code> dans une boucle. </li>
|
|
|
|
|
|
2007-07-17 12:01:59 +02:00
|
|
|
|
<li> Remarquez les derni<6E>res lignes du script<70>: <code>$HOME</code>
|
2005-06-03 15:56:21 +02:00
|
|
|
|
est cit<69> dans des guillemets simples, alors que <code>$PWD</code> est
|
|
|
|
|
cit<EFBFBD> entre guillemets doubles. Par cons<6E>quent, $HOME ne sera pas
|
2007-07-17 12:01:59 +02:00
|
|
|
|
interpr<EFBFBD>t<EFBFBD> (le mot <20><>$HOME<4D><45> appara<72>tra tel quel), tandis que
|
2005-06-03 15:56:21 +02:00
|
|
|
|
<code>$PWD</code> sera interpr<70>t<EFBFBD> (il sera remplac<61>, par exemple, par
|
|
|
|
|
<code>/home/toto</code>).</li>
|
|
|
|
|
</ol>
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
<h3>La boucle <code>case</code></h3>
|
|
|
|
|
|
2007-07-17 12:01:59 +02:00
|
|
|
|
<h4>Quand pr<70>f<EFBFBD>rer <code>case</code> <20> <code>if</code><3E>?</h4>
|
2005-06-03 15:56:21 +02:00
|
|
|
|
|
|
|
|
|
<p>La boucle <code>if</code> est tr<74>s pratique, mais devient rapidement
|
|
|
|
|
illisible lorsqu'un aiguillage offre plusieurs sorties, et que l'on doit
|
|
|
|
|
r<EFBFBD>p<EFBFBD>ter une condition pusieurs fois sous des formes <20> peine
|
|
|
|
|
diff<EFBFBD>rentes. Typiquement, un programme comme celui-ci est p<>nible <20>
|
2007-07-17 12:01:59 +02:00
|
|
|
|
<EFBFBD>crire, <20> lire et <20> d<>buguer<65>:</p>
|
2005-06-03 15:56:21 +02:00
|
|
|
|
|
|
|
|
|
<pre>
|
|
|
|
|
if test $PWD = $HOME
|
|
|
|
|
then echo "Vous <20>tes dans votre r<>pertoire d'accueil."
|
|
|
|
|
elif test $PWD = $HOME/bin
|
|
|
|
|
then echo "Vous <20>tes dans votre r<>pertoire d'ex<65>cutables."
|
|
|
|
|
elif test $PWD = $HOME/bin/solaris
|
|
|
|
|
then echo "Vous <20>tes dans votre r<>pertoire d'ex<65>cutables pour Solaris."
|
|
|
|
|
elif test $PWD = $HOME/prive
|
|
|
|
|
then echo "Vous <20>tes dans votre r<>pertoire priv<69>."
|
|
|
|
|
else echo 'Vous <20>tes dans un r<>pertoire quelconque, qui n'est ni $HOME,'
|
|
|
|
|
echo 'ni $HOME/bin, ni $HOME/bin/solaris. '"Vous <20>tes dans $PWD."
|
|
|
|
|
fi
|
|
|
|
|
</pre>
|
|
|
|
|
|
|
|
|
|
<p>Pourquoi ce programme est-il p<>nible <20> <20>crire, <20> lire et <20>
|
2007-07-17 12:01:59 +02:00
|
|
|
|
d<EFBFBD>buguer<EFBFBD>?</p>
|
2005-06-03 15:56:21 +02:00
|
|
|
|
|
|
|
|
|
<ol>
|
|
|
|
|
|
|
|
|
|
<li> parce qu'on a du mal, en le survolant simplement, <20> saisir
|
2007-07-17 12:01:59 +02:00
|
|
|
|
imm<EFBFBD>diatement son enjeu<65>; </li>
|
2005-06-03 15:56:21 +02:00
|
|
|
|
|
2007-07-17 12:01:59 +02:00
|
|
|
|
<li> parce qu'il y a une redondance de la s<>quence <20><><code>test
|
|
|
|
|
$PWD =</code><3E><><EFBFBD>; et qui dit redondance dit possibilit<69> de
|
|
|
|
|
faute de frappe<70>– erreur particuli<6C>rement difficile <20> rep<65>rer
|
|
|
|
|
<EFBFBD> l'œil nu<6E>;</li>
|
2005-06-03 15:56:21 +02:00
|
|
|
|
|
|
|
|
|
<li> parce que les diff<66>rentes conditions ne sont pas mises sur le m<>me
|
|
|
|
|
plan (<code>if</code> n'est pas, dans la boucle, sur le m<>me plan que
|
|
|
|
|
<code>elif</code>, alors que logiquement les deux instructions le
|
|
|
|
|
sont), ce qui nuit <20> la lisibilit<69>.</li>
|
|
|
|
|
|
|
|
|
|
</ol>
|
|
|
|
|
|
|
|
|
|
<p>La boucle <code>case</code> entend rem<65>dier <20> ces inconv<6E>nients. Il
|
|
|
|
|
s'agit tout simplement de la simplification d'un usage fr<66>quent de la
|
|
|
|
|
structure <code>if</code>. On peut r<>crire le programme suivant avec
|
2007-07-17 12:01:59 +02:00
|
|
|
|
<code>case</code><3E>:</p>
|
2005-06-03 15:56:21 +02:00
|
|
|
|
|
|
|
|
|
<pre>
|
|
|
|
|
case "$PWD" in
|
|
|
|
|
"$HOME") echo "Vous <20>tes dans votre r<>pertoire d'accueil.";;
|
|
|
|
|
"$HOME/bin") echo "Vous <20>tes dans votre r<>pertoire d'ex<65>cutables.";;
|
|
|
|
|
"$HOME/bin/solaris") echo "Vous <20>tes dans votre r<>pertoire d'ex<65>cutables pour Solaris.";;
|
|
|
|
|
"$HOME/prive") echo "Vous <20>tes dans votre r<>pertoire priv<69>.";;
|
|
|
|
|
"*") echo 'Vous <20>tes dans un r<>pertoire quelconque, qui n'est ni $HOME,'
|
|
|
|
|
echo 'ni $HOME/bin, ni $HOME/bin/solaris. '"Vous <20>tes dans $PWD.";;
|
|
|
|
|
esac
|
|
|
|
|
</pre>
|
|
|
|
|
|
|
|
|
|
<p>Le gain de lisibilit<69> est flagrant (si si, c'est flagrant, je vous
|
2007-07-17 12:01:59 +02:00
|
|
|
|
assure)<29>:</p>
|
2005-06-03 15:56:21 +02:00
|
|
|
|
|
|
|
|
|
<ol>
|
|
|
|
|
<li> la structure de la boucle et son enjeu sont
|
2007-07-17 12:01:59 +02:00
|
|
|
|
transparents<EFBFBD>;</li>
|
2005-06-03 15:56:21 +02:00
|
|
|
|
|
|
|
|
|
<li> la variable que l'on teste n'est cit<69>e qu'une seule fois, au lieu
|
2007-07-17 12:01:59 +02:00
|
|
|
|
d'<27>tre r<>p<EFBFBD>t<EFBFBD>e <20> chaque instruction <code>elif</code><3E>;</li>
|
2005-06-03 15:56:21 +02:00
|
|
|
|
|
|
|
|
|
<li>les valeurs possibles sont cit<69>es <20> la suite, et toutes sur le m<>me
|
|
|
|
|
plan.</li>
|
|
|
|
|
</ol>
|
|
|
|
|
|
|
|
|
|
<h4>Syntaxe de <code>case</code></h4>
|
|
|
|
|
|
2007-07-17 12:01:59 +02:00
|
|
|
|
<p>La boucle <code>case</code> adopte la syntaxe suivante<74>:</p>
|
2005-06-03 15:56:21 +02:00
|
|
|
|
|
|
|
|
|
<pre>
|
|
|
|
|
case <em>cha<68>ne</em> in
|
|
|
|
|
<em>motif</em>) <em>commandes</em> ;;
|
|
|
|
|
<em>motif</em>) <em>commandes</em> ;;
|
|
|
|
|
esac
|
|
|
|
|
</pre>
|
|
|
|
|
|
|
|
|
|
<p>
|
|
|
|
|
La boucle <code>case</code> commence par <20>valuer la
|
|
|
|
|
<em>cha<68>ne</em>. Ensuite, elle va lire chaque <em>motif</em>. Enfin, et
|
|
|
|
|
d<EFBFBD>s qu'une <em>cha<68>ne</em> correspond au <em>motif</em>, elle ex<65>cute
|
|
|
|
|
les <em>commandes</em> appropri<72>es. En anglais, <em>case</em> signifie
|
2007-07-17 12:01:59 +02:00
|
|
|
|
<EFBFBD><EFBFBD>cas<EFBFBD><EFBFBD><EFBFBD>; cette structure de contr<74>le permet en effet de
|
|
|
|
|
r<EFBFBD>agir ad<61>quatement aux diff<66>rents <20><>cas de figure<72><65>
|
2005-06-03 15:56:21 +02:00
|
|
|
|
possibles.</p>
|
|
|
|
|
|
|
|
|
|
<p>
|
2007-07-17 12:01:59 +02:00
|
|
|
|
Vous observerez que<75>:
|
2005-06-03 15:56:21 +02:00
|
|
|
|
</p>
|
|
|
|
|
|
|
|
|
|
<ul>
|
|
|
|
|
<li> le <em>motif</em> est s<>par<61> des commandes par une parenth<74>se
|
2007-07-17 12:01:59 +02:00
|
|
|
|
fermante (qui n'est ouverte nulle part<72>!)<29>;</li>
|
2005-06-03 15:56:21 +02:00
|
|
|
|
|
|
|
|
|
<li> la s<>rie des <em>commandes</em> est close par deux points et
|
2007-07-17 12:01:59 +02:00
|
|
|
|
virgules successifs<66>(<28><>;;<3B><>)<29>; </li>
|
2005-06-03 15:56:21 +02:00
|
|
|
|
|
|
|
|
|
<li> la boucle <code>case</code> est close par l'instruction
|
|
|
|
|
<code>esac</code>, qui n'est autre que le mot <code>case</code> <20>
|
|
|
|
|
l'envers (de m<>me que la boucle <code>if</code> est termin<69>e par
|
2007-07-17 12:01:59 +02:00
|
|
|
|
l'instruction<6F><code>fi</code>).</li>
|
2005-06-03 15:56:21 +02:00
|
|
|
|
</ul>
|
|
|
|
|
|
|
|
|
|
<p>
|
|
|
|
|
Un <em>motif</em> (<em>pattern</em>) est un mot contenant <20>ventuellement
|
|
|
|
|
les constructions <code>*</code>, <code>?</code>, <code>[a-d]</code>,
|
|
|
|
|
avec la m<>me signification que pour les raccourcis dans les noms de
|
2007-07-17 12:01:59 +02:00
|
|
|
|
fichiers (les <em>jokers</em>). Exemple<6C>:
|
2005-06-03 15:56:21 +02:00
|
|
|
|
</p>
|
|
|
|
|
|
|
|
|
|
<pre>
|
|
|
|
|
case $var in
|
|
|
|
|
[0-9]*) echo "$var est un nombre.";;
|
|
|
|
|
[a-zA-Z]*) echo "$var est un mot.";;
|
|
|
|
|
*) echo "$var n'est ni un nombre ni un mot.";;
|
|
|
|
|
esac</pre>
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
<h4>L'aiguillage commun <20> plusieurs motifs</h4>
|
|
|
|
|
|
|
|
|
|
<p>Que faire si je veux aiguiller plusieurs motifs diff<66>rents de la m<>me
|
2007-07-17 12:01:59 +02:00
|
|
|
|
fa<EFBFBD>on<EFBFBD>? Le premier r<>flexe est de r<>p<EFBFBD>ter, presque <20> l'identique,
|
|
|
|
|
des lignes, de la fa<66>on suivante<74>:</p>
|
2005-06-03 15:56:21 +02:00
|
|
|
|
|
|
|
|
|
<pre>
|
|
|
|
|
#!/bin/sh
|
|
|
|
|
# Fichier "canards"
|
|
|
|
|
|
2007-07-17 12:01:59 +02:00
|
|
|
|
echo "Quel est ton nom<6F>?"
|
2005-06-03 15:56:21 +02:00
|
|
|
|
read nom
|
|
|
|
|
|
|
|
|
|
case $nom in <strong>
|
|
|
|
|
"Riri") echo "Ton oncle s'appelle Donald, Riri.";;
|
|
|
|
|
"Fifi") echo "Ton oncle s'appelle Donald, Fifi.";;
|
|
|
|
|
"Loulou") echo "Ton oncle s'appelle Donald, Loulou.";;
|
|
|
|
|
</strong>"*") echo "Tu n'es pas un neveu de Donald.";;
|
|
|
|
|
esac
|
|
|
|
|
</pre>
|
|
|
|
|
|
|
|
|
|
<p>
|
|
|
|
|
Mais <strong>il n'est jamais bon de r<>p<EFBFBD>ter manuellement des lignes de
|
|
|
|
|
programmation</strong>, car c'est g<>n<EFBFBD>rateur de fautes. Il faut toujours
|
|
|
|
|
chercher des raccourcis, et ne se r<>p<EFBFBD>ter qu'en dernier recours. On
|
2007-07-17 12:01:59 +02:00
|
|
|
|
utilisera donc le caract<63>re <20><>|<7C><>, qui permet de mettre sur le
|
|
|
|
|
m<EFBFBD>me plan diff<66>rents motifs. On pourra donc <20>crire<72>:
|
2005-06-03 15:56:21 +02:00
|
|
|
|
</p>
|
|
|
|
|
|
|
|
|
|
<pre>
|
|
|
|
|
#!/bin/sh
|
|
|
|
|
# Fichier "canards"
|
|
|
|
|
|
2007-07-17 12:01:59 +02:00
|
|
|
|
echo "Quel est ton nom<6F>?"
|
2005-06-03 15:56:21 +02:00
|
|
|
|
read nom
|
|
|
|
|
|
|
|
|
|
case $nom in
|
|
|
|
|
<strong>"Riri"|"Fifi"|"Loulou"</strong>) echo "Ton oncle s'appelle Donald, <strong>$nom</strong>.";;
|
|
|
|
|
"*") echo "Tu n'es pas un neveu de Donald.";;
|
|
|
|
|
esac
|
|
|
|
|
</pre>
|
|
|
|
|
|
|
|
|
|
<p class="continue">On gagne ainsi en concision, et on <20>vite bien des
|
|
|
|
|
fautes d'inattention, qui sont particuli<6C>rement coriaces <20> d<>buguer.
|
|
|
|
|
</p>
|
|
|
|
|
|
|
|
|
|
<div class="attention">
|
|
|
|
|
<p>La boucle <code>case</code> ex<65>cute les commandes correspondant au
|
|
|
|
|
<strong>premier</strong> motif correct, et ne parcourt pas les motifs
|
|
|
|
|
suivants si elle en a trouv<75> un. Par cons<6E>quent, <strong>si le dernier
|
2007-07-17 12:01:59 +02:00
|
|
|
|
motif est <20><>*<2A><>, cela revient <20> l'instruction
|
2005-06-03 15:56:21 +02:00
|
|
|
|
<code>else</code> dans la boucle <code>if</code></strong>.</p>
|
|
|
|
|
</div>
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
2007-07-17 12:01:59 +02:00
|
|
|
|
<h2>R<>p<EFBFBD>ter une proc<6F>dure<72>: <code>while</code>, <code>until</code>
|
|
|
|
|
et<EFBFBD><code>for</code></h2>
|
2005-06-03 15:56:21 +02:00
|
|
|
|
|
|
|
|
|
<p>Les structures <code>if</code> et <code>case</code> sont des
|
2007-07-17 12:01:59 +02:00
|
|
|
|
structures d'aiguillage<67>; les structures <code>while</code>,
|
2005-06-03 15:56:21 +02:00
|
|
|
|
<code>until</code> et <code>for</code> sont proprement des
|
|
|
|
|
boucles. C'est-<2D>-dire qu'elles soumettent <20> une condition d<>termin<69>e la
|
|
|
|
|
r<EFBFBD>p<EFBFBD>tition (ou non) d'une suite de commandes.</p>
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
<h3>La boucle <code>while</code></h3>
|
|
|
|
|
|
|
|
|
|
<p>
|
|
|
|
|
La boucle <code>while</code> ex<65>cute les <em>commandes</em> de mani<6E>re
|
2007-07-17 12:01:59 +02:00
|
|
|
|
r<EFBFBD>p<EFBFBD>t<EFBFBD>e tant que la premi<6D>re <em>commande</em> r<>ussit<69>; en
|
|
|
|
|
anglais, <em>while</em> signifie <20><>tant que<75><65>.</p>
|
2005-06-03 15:56:21 +02:00
|
|
|
|
|
|
|
|
|
|
|
|
|
|
<h4>Syntaxe de <code>while</code></h4>
|
|
|
|
|
|
2007-07-17 12:01:59 +02:00
|
|
|
|
<p>La boucle <code>while</code> adopte la syntaxe suivante<74>:</p>
|
2005-06-03 15:56:21 +02:00
|
|
|
|
|
|
|
|
|
<pre>while <em>condition</em>
|
|
|
|
|
do <em>commandes</em>
|
|
|
|
|
done</pre>
|
|
|
|
|
|
|
|
|
|
<p><strong>Apr<70>s l'instruction <code>do</code>, vous pouvez mettre
|
|
|
|
|
autant de commandes que vous le d<>sirez</strong>, suivies de retours
|
2007-07-17 12:01:59 +02:00
|
|
|
|
chariot ou bien de points et virgules (<28><>;<3B><>). Le shell
|
2005-06-03 15:56:21 +02:00
|
|
|
|
ex<EFBFBD>cutera tout ce qu'il trouve, jusqu'<27> ce qu'il tombe sur l'instruction
|
|
|
|
|
<code>done</code>. </p>
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
<h4>Exemple</h4>
|
|
|
|
|
|
|
|
|
|
<pre>
|
2007-07-17 12:01:59 +02:00
|
|
|
|
echo "Tapez le mot de passe<73>:"
|
2005-06-03 15:56:21 +02:00
|
|
|
|
read password
|
|
|
|
|
|
|
|
|
|
while test "$password" != <em>mot de passe correct</em>
|
|
|
|
|
do echo "Mot de passe incorrect."
|
|
|
|
|
echo "Tapez le mot de passe"
|
|
|
|
|
read password
|
|
|
|
|
done
|
|
|
|
|
|
|
|
|
|
echo "Mot de passe correct."
|
|
|
|
|
echo "Bienvenue sur les ordinateurs secrets du Pentagone."
|
|
|
|
|
</pre>
|
|
|
|
|
|
|
|
|
|
<p class="continue"> Les lignes qui suivent la boucle <code>while</code>
|
|
|
|
|
seront ex<65>cut<75>es si, et seulement si, la condition est remplie,
|
|
|
|
|
c'est-<2D>-dire si l'utilisateur tape le bon mot de passe. (En pratique, il
|
|
|
|
|
est tr<74>s fortement d<>conseill<6C> de taper un mot de passe en clair dans un
|
2007-07-17 12:01:59 +02:00
|
|
|
|
script, car rien n'est plus facile que de l'<27>diter<65>!...).
|
2005-06-03 15:56:21 +02:00
|
|
|
|
</p>
|
|
|
|
|
|
|
|
|
|
<h4>Un usage concret de <code>while</code></h4>
|
|
|
|
|
|
|
|
|
|
<p>Supposons que vous vouliez cr<63>er cinquante fichiers sous la forme
|
|
|
|
|
<code>fichier1</code>, <code>fichier2</code>, <code>fichier3</code>,
|
|
|
|
|
etc. Un petit script vous fera <20>a plus vite que cinquante lignes de
|
|
|
|
|
commande. </p>
|
|
|
|
|
|
|
|
|
|
<pre>
|
|
|
|
|
#!/bin/sh
|
|
|
|
|
# Fichier "50fichiers"
|
|
|
|
|
|
|
|
|
|
numero=1
|
|
|
|
|
|
|
|
|
|
while test $numero != 51
|
|
|
|
|
do
|
|
|
|
|
# la commande "touch" permet de cr<63>er un fichier vide :
|
|
|
|
|
touch fichier"$numero"
|
|
|
|
|
|
|
|
|
|
# cette commande ajoute 1 <20> la variable "numero" :
|
|
|
|
|
numero=$(($numero + 1))
|
|
|
|
|
done
|
|
|
|
|
</pre>
|
|
|
|
|
|
|
|
|
|
<p class="continue">Avec ce script, la variable <code>numero</code> est
|
2007-07-17 12:01:59 +02:00
|
|
|
|
d'abord cr<63><72>e avec la valeur<75>1. Ensuite, le shell examine si la
|
|
|
|
|
valeur de <code>numero</code> est diff<66>rente de<64>51<35>; c'est le
|
|
|
|
|
cas. Par cons<6E>quent, le shell ex<65>cute les commandes suivantes<65>: il
|
|
|
|
|
cr<EFBFBD>e un fichier <code>fichier1</code>, puis ajoute<74>1 <20> la variable
|
|
|
|
|
<code>numero</code>, qui vaut donc<6E>2. Et c'est reparti pour un
|
|
|
|
|
tour<EFBFBD>! Le shell examine si la valeur de <code>numero</code>,
|
|
|
|
|
c'est-<2D>-dire<72>2, est diff<66>rente de<64>51, etc.
|
2005-06-03 15:56:21 +02:00
|
|
|
|
</p>
|
|
|
|
|
|
|
|
|
|
<p>Petit conseil pour faire les choses le plus proprement
|
2007-07-17 12:01:59 +02:00
|
|
|
|
possible<EFBFBD>: dans le script qui pr<70>c<EFBFBD>de,
|
|
|
|
|
remplacez<EFBFBD><EFBFBD><EFBFBD>51<EFBFBD><EFBFBD> par une variable<6C>: le script sera
|
|
|
|
|
beaucoup plus lisible. Exemple<6C>:</p>
|
2005-06-03 15:56:21 +02:00
|
|
|
|
|
|
|
|
|
<pre>
|
|
|
|
|
#!/bin/sh
|
|
|
|
|
# Fichier "50fichiers"
|
|
|
|
|
|
|
|
|
|
numero=1
|
|
|
|
|
<strong>limite=51</strong>
|
|
|
|
|
|
|
|
|
|
while test $numero != <strong>$limite</strong>
|
|
|
|
|
do
|
|
|
|
|
# la commande "touch" permet de cr<63>er un fichier vide :
|
|
|
|
|
touch fichier"$numero"
|
|
|
|
|
|
|
|
|
|
# cette commande ajoute 1 <20> la variable "numero" :
|
|
|
|
|
numero=$(($numero + 1))
|
|
|
|
|
done
|
|
|
|
|
</pre>
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
<h3>La boucle <code>until</code></h3>
|
|
|
|
|
|
|
|
|
|
<p>
|
2007-07-17 12:01:59 +02:00
|
|
|
|
<em>Until</em> signifie <20><>jusqu'<27> ce que<75><65> en anglais. Cette
|
2005-06-03 15:56:21 +02:00
|
|
|
|
boucle est le pendant de la boucle <code>while</code>, <20> ceci pr<70>s que
|
|
|
|
|
<strong>la <em>condition</em> ne d<>termine pas la cause de la r<>p<EFBFBD>tition
|
|
|
|
|
de la boucle, mais celle de son interruption</strong>.</p>
|
|
|
|
|
|
|
|
|
|
<h4>Syntaxe de <code>until</code></h4>
|
|
|
|
|
|
|
|
|
|
<pre>
|
|
|
|
|
until <em>condition</em>
|
|
|
|
|
do <em>commandes</em>
|
|
|
|
|
done
|
|
|
|
|
</pre>
|
|
|
|
|
|
|
|
|
|
<h4>Exemple</h4>
|
|
|
|
|
|
2007-07-17 12:01:59 +02:00
|
|
|
|
<p> On aura ainsi<73>: </p>
|
2005-06-03 15:56:21 +02:00
|
|
|
|
|
|
|
|
|
<pre>
|
2007-07-17 12:01:59 +02:00
|
|
|
|
echo "Tapez le mot de passe<73>:"
|
2005-06-03 15:56:21 +02:00
|
|
|
|
read password
|
|
|
|
|
|
|
|
|
|
<strong>until test $password = <em>mot de passe correct</em></strong>
|
|
|
|
|
do echo "Mot de passe incorrect."
|
|
|
|
|
echo "Tapez le mot de passe"
|
|
|
|
|
read password
|
|
|
|
|
done
|
|
|
|
|
|
|
|
|
|
echo "Mot de passe correct."
|
|
|
|
|
echo "Bienvenue sur les ordinateurs secrets de la NASA."
|
|
|
|
|
</pre>
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
<p> Il revient en effet au m<>me de r<>p<EFBFBD>ter une suite de commandes
|
2007-07-17 12:01:59 +02:00
|
|
|
|
<EFBFBD><EFBFBD><em>tant que</em> le mot de passe est
|
|
|
|
|
<strong>incorrect</strong><3E><> ou bien <20><><em>jusqu'<27> ce que</em>
|
|
|
|
|
le mot de passe soit <strong>correct</strong><3E><>, car un mot de
|
2005-06-03 15:56:21 +02:00
|
|
|
|
passe d<>termin<69> ne peut <20>tre que correct ou incorrect.
|
|
|
|
|
</p>
|
|
|
|
|
|
|
|
|
|
|
2007-07-17 12:01:59 +02:00
|
|
|
|
<h4><code>while</code> ou <code>until</code><3E>?</h4>
|
2005-06-03 15:56:21 +02:00
|
|
|
|
|
|
|
|
|
<p>Vous allez donc me demander que pr<70>f<EFBFBD>rer entre <code>while</code> et
|
2007-07-17 12:01:59 +02:00
|
|
|
|
<code>until</code>, si les deux sont si souvent <20>quivalentes<65>? Eh
|
2005-06-03 15:56:21 +02:00
|
|
|
|
bien, celle dont la condition sera la plus facile <20> <20>crire, <20> lire et <20>
|
|
|
|
|
d<EFBFBD>buguer. Si, comme dans notre exemple, elles sont aussi simples
|
|
|
|
|
l'une que l'autre, choisissez votre pr<70>f<EFBFBD>r<EFBFBD>e ou prenez-en une au hasard.
|
|
|
|
|
</p>
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
<h3>La boucle <code>for</code></h3>
|
|
|
|
|
|
|
|
|
|
<p>
|
|
|
|
|
La boucle <code>for</code> affecte successivement une variable chaque
|
|
|
|
|
cha<EFBFBD>ne de caract<63>res trouv<75>e dans une <em>liste de cha<68>nes</em>, et
|
|
|
|
|
ex<EFBFBD>cute les <em>commandes</em> une fois pour chaque cha<68>ne.
|
|
|
|
|
</p>
|
|
|
|
|
|
|
|
|
|
<h4>Syntaxe de <code>for</code></h4>
|
|
|
|
|
|
|
|
|
|
<pre>for <em>var</em> in <em>liste de cha<68>nes</em>
|
|
|
|
|
do <em>commandes</em>
|
|
|
|
|
done</pre>
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
<h4>Exemple</h4>
|
|
|
|
|
|
|
|
|
|
<pre>
|
|
|
|
|
#!/bin/sh
|
|
|
|
|
# Fichier "liste"
|
|
|
|
|
|
|
|
|
|
for element in *
|
|
|
|
|
do echo "$element"
|
|
|
|
|
done
|
|
|
|
|
</pre>
|
|
|
|
|
|
|
|
|
|
<p class="continue">
|
|
|
|
|
affiche les noms de tous les fichiers du r<>pertoire courant, un par ligne.
|
|
|
|
|
</p>
|
|
|
|
|
|
|
|
|
|
<p>Concr<63>tement, le shell va prendre la liste des cha<68>nes, en
|
2007-07-17 12:01:59 +02:00
|
|
|
|
l'occurrence <20><>*<2A><>, c'est-<2D>-dire tous les fichiers et
|
2005-06-03 15:56:21 +02:00
|
|
|
|
r<EFBFBD>pertoires du r<>pertoire courant. <20> chacun de ces <20>l<EFBFBD>ments, il va
|
|
|
|
|
attribuer la variable <code>element</code>, puis ex<65>cuter les commandes
|
|
|
|
|
sp<EFBFBD>cifi<EFBFBD>es, en l'occurrence <code>echo
|
|
|
|
|
"$element"</code>. Ainsi, si dans mon r<>pertoire j'ai les
|
|
|
|
|
fichiers <code>a</code>, <code>b</code> et <code>c</code>, le shell va
|
|
|
|
|
ex<EFBFBD>cuter successivement <code>echo "a"</code>, <code>echo
|
|
|
|
|
"b"</code> et <code>echo "c"</code>. </p>
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
<h4>Usage de <code>for</code></h4>
|
|
|
|
|
<p>
|
|
|
|
|
Comme <code>while</code> et <code>until</code>, <code>for</code> est une
|
|
|
|
|
boucle au sens propre. Mais il y a une diff<66>rence notable entre ces deux
|
2007-07-17 12:01:59 +02:00
|
|
|
|
groupes de boucle<6C>: <code>while</code> et <code>until</code> sont
|
2005-06-03 15:56:21 +02:00
|
|
|
|
plus appropri<72>s <20> la r<>p<EFBFBD>tition <em><3E> l'identique</em> d'une s<>quence de
|
|
|
|
|
commandes, tandis que <strong><code>for</code> convient particuli<6C>rement
|
|
|
|
|
aux r<>p<EFBFBD>titions soumises <20> de l<>g<EFBFBD>res variations</strong>.
|
|
|
|
|
</p>
|
|
|
|
|
|
|
|
|
|
<p>
|
|
|
|
|
Prenons par exemple le script qui permettait, avec <code>while</code>,
|
|
|
|
|
de cr<63>er 50 fichiers rapidement. La num<75>ration des passages par la
|
2007-07-17 12:01:59 +02:00
|
|
|
|
boucle <20>tait assez p<>nible, et <20>clat<61>e en trois endroits<74>:
|
2005-06-03 15:56:21 +02:00
|
|
|
|
</p>
|
|
|
|
|
|
|
|
|
|
<ol>
|
2007-07-17 12:01:59 +02:00
|
|
|
|
<li> avant la boucle<6C>: l'affectation de la valeur<75>1 <20> la
|
|
|
|
|
variable <code>numero</code> (et, <20>ventuellement, de la valeur<75>51 <20>
|
|
|
|
|
la variable <code>limite</code>)<29>;</li>
|
2005-06-03 15:56:21 +02:00
|
|
|
|
|
|
|
|
|
<li> eu d<>but de la boucle, la condition
|
2007-07-17 12:01:59 +02:00
|
|
|
|
<code>test<73>$numero<72>!=<3D>51</code> ou
|
|
|
|
|
<code>test<73>$numero<72>!=<3D>$limite</code><3E>;</li>
|
2005-06-03 15:56:21 +02:00
|
|
|
|
|
|
|
|
|
<li> <20> la fin de la boucle, l'incr<63>mentation (c'est-<2D>-dire
|
|
|
|
|
l'augmentation r<>guli<6C>re) de la variable <code>numero</code>, avec la
|
2007-07-17 12:01:59 +02:00
|
|
|
|
ligne <code>numero=$(($numero<72>+<2B>1))</code>.</li>
|
2005-06-03 15:56:21 +02:00
|
|
|
|
</ol>
|
|
|
|
|
|
|
|
|
|
<p>
|
|
|
|
|
Pourquoi dire en trois fois ce qui, dans les langages naturels
|
2007-07-17 12:01:59 +02:00
|
|
|
|
(c'est-<2D>-dire humains), s'<27>nonce en une seule<6C>: <20><>r<EFBFBD>p<EFBFBD>ter
|
|
|
|
|
<em>n</em> fois cette s<>quence de commandes<65><73><EFBFBD>? La boucle
|
|
|
|
|
<code>for</code> se r<>v<EFBFBD>le alors indispensable<6C>:
|
2005-06-03 15:56:21 +02:00
|
|
|
|
</p>
|
|
|
|
|
|
|
|
|
|
<pre>
|
|
|
|
|
#!/bin/sh
|
|
|
|
|
# Fichier "50fichiers-for"
|
|
|
|
|
|
|
|
|
|
# la commande "seq <em>a</em> <em>b</em>" compte de <em>a</em> <20> <em>b</em>
|
|
|
|
|
for numero in `seq 1 50`
|
|
|
|
|
do touch fichier"$numero"
|
|
|
|
|
done
|
|
|
|
|
</pre>
|
|
|
|
|
|
|
|
|
|
<p class="continue">Avouez que le script est beaucoup plus simple de
|
2007-07-17 12:01:59 +02:00
|
|
|
|
cette mani<6E>re<72>!</p>
|
2005-06-03 15:56:21 +02:00
|
|
|
|
|
|
|
|
|
|
2005-06-03 16:59:10 +02:00
|
|
|
|
|
2007-07-17 12:01:59 +02:00
|
|
|
|
<h2>D<>finir une variable<6C>: <code>select</code></h2>
|
2005-06-03 16:59:10 +02:00
|
|
|
|
|
|
|
|
|
<p>
|
|
|
|
|
Il est parfois utile de donner <20> l'utilisateur du script des formulaires
|
|
|
|
|
sous forme de <strong>questions <20> choix multiples</strong>.</p>
|
|
|
|
|
|
|
|
|
|
<p> Par exemple, je suis sociologue et je veux dresser des statistiques
|
2007-07-17 12:01:59 +02:00
|
|
|
|
sur les opinions d'un <20>chantillon repr<70>sentatif de normaliens<6E>:
|
2005-06-03 16:59:10 +02:00
|
|
|
|
sont-ils favorables ou d<>favorables <20> la destruction du NIR (Nouveau
|
|
|
|
|
Pavillon Rataud) et <20> la reconstruction du VIR (Vieux Pavillon
|
2007-07-17 12:01:59 +02:00
|
|
|
|
Rataud)<29>?
|
2005-06-03 16:59:10 +02:00
|
|
|
|
</p>
|
|
|
|
|
|
|
|
|
|
<p>
|
2007-07-17 12:01:59 +02:00
|
|
|
|
Spontan<EFBFBD>ment, je fais le script suivant<6E>:
|
2005-06-03 16:59:10 +02:00
|
|
|
|
</p>
|
|
|
|
|
|
|
|
|
|
<pre>
|
|
|
|
|
#!/bin/sh
|
|
|
|
|
# Fichier "vote-nir"
|
|
|
|
|
|
2007-07-17 12:01:59 +02:00
|
|
|
|
echo "<3B>tes-vous favorable au remplacement du NIR par le VIR<49>?"
|
|
|
|
|
echo "(R<>pondez <20><>pour<75><72> ou <20><>contre<72><65>)"
|
2005-06-03 16:59:10 +02:00
|
|
|
|
read opinion
|
|
|
|
|
|
|
|
|
|
# M'envoyer le r<>sultat par mail
|
|
|
|
|
echo "$opinion" | mail bourdieu
|
|
|
|
|
</pre>
|
|
|
|
|
|
|
|
|
|
<p>Seulement voil<69>, de nombreuses personnes vont faire des fautes de
|
2007-07-17 12:01:59 +02:00
|
|
|
|
frappe, et taper <20><>poru<72><75> au lieu de <20><>pour<75><72>,
|
|
|
|
|
<EFBFBD><EFBFBD>cnotre<EFBFBD><EFBFBD> au lieu de <20><>contre<72><65>,
|
|
|
|
|
etc. R<>sultat<61>: au lieu de laisser d'autres scripts traiter
|
2005-06-03 16:59:10 +02:00
|
|
|
|
automatiquement les r<>sultats des statistiques qui me sont envoy<6F>s par
|
|
|
|
|
courriel, je devrai tout regarder <20> la main et cocher moi-m<>me les
|
|
|
|
|
r<EFBFBD>sultats pour ne pas en oublier. Dans ce cas, autant faire un sondage
|
2007-07-17 12:01:59 +02:00
|
|
|
|
classique <20> la sortie du Pot<6F>!</p>
|
2005-06-03 16:59:10 +02:00
|
|
|
|
|
2007-07-17 12:01:59 +02:00
|
|
|
|
<p>Heureusement, il existe une parade<64>: la boucle
|
2005-06-03 16:59:10 +02:00
|
|
|
|
<code>select</code>. </p>
|
|
|
|
|
|
|
|
|
|
<h4>Syntaxe de <code>select</code></h4>
|
|
|
|
|
|
|
|
|
|
<pre>
|
|
|
|
|
select <em>variable</em> in <em>valeurs possibles</em>
|
|
|
|
|
do <em>commandes</em>
|
|
|
|
|
done
|
|
|
|
|
</pre>
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
<h4>Questions <20> choix multiples</h4>
|
|
|
|
|
|
|
|
|
|
<p>
|
2007-07-17 12:01:59 +02:00
|
|
|
|
Voici le script de notre sociologue<75>:
|
2005-06-03 16:59:10 +02:00
|
|
|
|
</p>
|
|
|
|
|
|
|
|
|
|
<pre>
|
|
|
|
|
#!/bin/sh
|
|
|
|
|
# Fichier "vote-nir"
|
|
|
|
|
|
2007-07-17 12:01:59 +02:00
|
|
|
|
echo "<3B>tes-vous favorable au remplacement du NIR par le VIR<49>?"
|
2005-06-03 16:59:10 +02:00
|
|
|
|
select opinion in Pour Contre
|
|
|
|
|
do break
|
|
|
|
|
done
|
|
|
|
|
|
|
|
|
|
# M'envoyer le r<>sultat par mail
|
|
|
|
|
echo "$opinion" | mail bourdieu
|
|
|
|
|
</pre>
|
|
|
|
|
|
|
|
|
|
<p class="continue">
|
2007-07-17 12:01:59 +02:00
|
|
|
|
Les utilisateurs verront alors<72>:
|
2005-06-03 16:59:10 +02:00
|
|
|
|
</p>
|
|
|
|
|
|
|
|
|
|
<pre>
|
|
|
|
|
<EFBFBD>tes-vous favorable au remplacement du NIR par le VIR ?
|
|
|
|
|
1) Pour
|
|
|
|
|
2) Contre
|
|
|
|
|
</pre>
|
|
|
|
|
|
|
|
|
|
<p class="continue">
|
2007-07-17 12:01:59 +02:00
|
|
|
|
Ils devront alors taper<65>1 ou<6F>2, selon leur opinion.
|
2005-06-03 16:59:10 +02:00
|
|
|
|
</p>
|
|
|
|
|
|
|
|
|
|
<p>Vous avez remarqu<71> que l'instruction <code>do</code> est suivie de la
|
|
|
|
|
commande <code>break</code>. Celle-ci indique de sortir de la boucle
|
|
|
|
|
<code>select</code>. Sans <code>break</code>, <code>select</code> est en
|
|
|
|
|
effet une boucle, comme <code>while</code>, <code>until</code> et
|
|
|
|
|
<code>for</code>. Nous allons voir pourquoi.</p>
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
<h4>Utiliser <code>select</code> comme boucle</h4>
|
|
|
|
|
<p>
|
|
|
|
|
Par d<>faut, <code>select</code> se comporte comme une boucle. Observons
|
2007-07-17 12:01:59 +02:00
|
|
|
|
le comportement du script suivant<6E>:
|
2005-06-03 16:59:10 +02:00
|
|
|
|
</p>
|
|
|
|
|
|
|
|
|
|
<pre>
|
|
|
|
|
#!/bin/sh
|
|
|
|
|
# Fichier "piege"
|
|
|
|
|
|
2007-07-17 12:01:59 +02:00
|
|
|
|
echo "Si tu arrives <20> sortir de ce script, je te donne 30<33>euros."
|
2005-06-03 16:59:10 +02:00
|
|
|
|
select issue in "Sortir" "Quitter"
|
|
|
|
|
# la commande "continue" est une commande vide : elle ne fait rien de sp<73>cial
|
|
|
|
|
do continue
|
|
|
|
|
done
|
|
|
|
|
</pre>
|
|
|
|
|
|
2007-07-17 12:01:59 +02:00
|
|
|
|
<p class="continue">Essayez maintenant d'ex<65>cuter ce script<70>:</p>
|
2005-06-03 16:59:10 +02:00
|
|
|
|
|
|
|
|
|
<pre>
|
|
|
|
|
Si tu arrives <20> sortir de ce script, je te donne 30 euros.
|
|
|
|
|
1) Sortir
|
|
|
|
|
2) Quitter
|
|
|
|
|
#? <em>1</em>
|
|
|
|
|
#? <em>2</em>
|
|
|
|
|
#? <em>1</em>
|
|
|
|
|
#? <em>2</em>
|
|
|
|
|
#? <em>1</em>
|
|
|
|
|
<em>(etc.)</em>
|
|
|
|
|
</pre>
|
|
|
|
|
|
|
|
|
|
<p>Ce comportement est parfois utile, par exemple si vous programmez un
|
|
|
|
|
petit jeu, ou autre. Ou encore, pour pr<70>venir les r<>ponses non
|
2007-07-17 12:01:59 +02:00
|
|
|
|
valides. Exemple<6C>:</p>
|
2005-06-03 16:59:10 +02:00
|
|
|
|
|
|
|
|
|
<pre>
|
|
|
|
|
#!/bin/sh
|
|
|
|
|
# Fichier "vote-nir"
|
|
|
|
|
|
2007-07-17 12:01:59 +02:00
|
|
|
|
echo "<3B>tes-vous favorable au remplacement du NIR par le VIR<49>?"
|
2005-06-03 16:59:10 +02:00
|
|
|
|
select opinion in Pour Contre
|
|
|
|
|
do
|
|
|
|
|
case $opinion in
|
|
|
|
|
# Laisser passer ceux qui r<>pondent correctement <20> la question
|
|
|
|
|
"Pour"|"Contre") break;;
|
|
|
|
|
|
|
|
|
|
# Au cas o<> des zozos tapent sur autre chose que 1 ou 2
|
|
|
|
|
"*") continue;;
|
|
|
|
|
esac
|
|
|
|
|
done
|
|
|
|
|
|
|
|
|
|
# M'envoyer le r<>sultat par mail
|
|
|
|
|
echo "$opinion" | mail bourdieu
|
|
|
|
|
</pre>
|
|
|
|
|
|
|
|
|
|
<p class="continue">Gr<47>ce <20> cela, si un normalien tape une r<>ponse
|
|
|
|
|
invalide, <code>select</code> attend qu'il tape quelque chose de
|
2007-07-17 12:01:59 +02:00
|
|
|
|
correct<EFBFBD>; s'il tape quelque chose de correct, la r<>ponse est
|
2005-06-03 16:59:10 +02:00
|
|
|
|
envoy<EFBFBD>e au sociologue.</p>
|
|
|
|
|
|
|
|
|
|
<div class="attention">
|
|
|
|
|
<p>
|
|
|
|
|
Vous aurez remarqu<71> au passage que <strong>l'on peut sans probl<62>me
|
|
|
|
|
imbriquer des structures de contr<74>le les unes dans les autres</strong>.
|
|
|
|
|
</p>
|
|
|
|
|
</div>
|
|
|
|
|
|
|
|
|
|
|
2005-06-03 15:56:21 +02:00
|
|
|
|
<h2><a name="retour">Code de retour</a></h2>
|
|
|
|
|
|
|
|
|
|
<p>
|
|
|
|
|
On remarque que la condition des commandes <code>if</code> et
|
|
|
|
|
<code>while</code> est une commande. Chaque commande renvoie un code de
|
|
|
|
|
retour (qui est ignor<6F> en utilisation normale). Si le code est 0, la
|
2007-07-17 12:01:59 +02:00
|
|
|
|
commande a r<>ussi<73>; sinon, la commande a <20>chou<6F>. Par exemple, le
|
2005-06-03 15:56:21 +02:00
|
|
|
|
compilateur <code>cc</code> renvoie un code d'erreur non nul si le
|
|
|
|
|
fichier compil<69> contient des erreurs, ou s'il n'existe pas.
|
|
|
|
|
</p>
|
|
|
|
|
|
|
|
|
|
<p>
|
|
|
|
|
Les commandes <code>if</code> et <code>while</code> consid<69>rent donc le
|
2007-07-17 12:01:59 +02:00
|
|
|
|
code de retour 0 comme <20><>vrai<61><69>, et tout autre code comme
|
|
|
|
|
<EFBFBD><EFBFBD>faux<EFBFBD><EFBFBD>.
|
2005-06-03 15:56:21 +02:00
|
|
|
|
</p>
|
|
|
|
|
|
|
|
|
|
<p>
|
|
|
|
|
Il existe une commande <code>test</code>, qui <20>value des expressions
|
|
|
|
|
bool<EFBFBD>ennes (c'est-<2D>-dire dont la valeur ne peut <20>tre que vraie ou
|
2005-09-08 01:00:03 +02:00
|
|
|
|
fausse) pass<73>es en argument, et renvoie un code de retour en fonction du
|
2007-07-17 12:01:59 +02:00
|
|
|
|
r<EFBFBD>sultat. Elle est bien utile pour les scripts. Exemple<6C>:
|
2005-06-03 15:56:21 +02:00
|
|
|
|
</p>
|
|
|
|
|
|
|
|
|
|
<pre>
|
|
|
|
|
if test $var = foo
|
|
|
|
|
then echo 'La variable vaut foo'
|
|
|
|
|
else echo 'La variable ne vaut pas foo'
|
|
|
|
|
fi</pre>
|
|
|
|
|
|
2005-09-08 01:00:03 +02:00
|
|
|
|
<p>
|
|
|
|
|
Pour en savoir plus sur les op<6F>rateurs de test, consultez la page <a
|
|
|
|
|
href="test.html">tests et calculs arithm<68>tiques</a> Ou bien vous pouvez
|
|
|
|
|
revenir <20> la <a href="index.html">page centrale sur le shell</a>, d'o<>
|
|
|
|
|
vous pourrez vous orienter vers d'autres parties du cours.
|
|
|
|
|
</p>
|
2005-06-03 15:56:21 +02:00
|
|
|
|
|
|
|
|
|
|
|
|
|
|
<div class="metainformation">
|
2007-07-17 12:01:59 +02:00
|
|
|
|
Auteur<EFBFBD>: Baptiste M<>l<EFBFBD>s.
|
|
|
|
|
Derni<EFBFBD>re modification le <date value="$Date: 2007-07-17 10:03:40 $" />.
|
2005-06-03 15:56:21 +02:00
|
|
|
|
</div>
|
|
|
|
|
|
|
|
|
|
</body>
|
|
|
|
|
</html>
|