424 lines
12 KiB
XML
424 lines
12 KiB
XML
<?xml version="1.0" encoding="ISO-8859-1"?>
|
||
<!DOCTYPE html
|
||
PUBLIC "-//ENS/Tuteurs//DTD TML 1//EN"
|
||
"tuteurs://DTD/tml.dtd">
|
||
<html>
|
||
<head>
|
||
<title>Tests</title>
|
||
</head>
|
||
<body>
|
||
|
||
<h1>Tests et calcul arithmétique</h1>
|
||
|
||
<h2>Qu'est-ce qu'un test ?</h2>
|
||
|
||
<p>
|
||
<strong>Un test est une opération dont le but est d'évaluer la valeur
|
||
d'une expression</strong>. Cette expression peut être simplement
|
||
l'<em>existence</em> de quelque chose (par exemple, d'un fichier, ou
|
||
bien d'une variable), ou ce peut être une <em>proposition</em>.</p>
|
||
|
||
<p>Concrètement, cela veut dire qu'<strong>un programme n'est pas limité
|
||
à la possibilité de donner des ordres : il peut aussi poser des
|
||
questions</strong>, et agir comme vous le décidez en fonction des
|
||
réponses apportées aux questions.</p>
|
||
|
||
<p>Posons par exemple le principe suivant : « Si Dieu n'existe
|
||
pas, alors tout est permis. » Nous allons ensuite tester si Dieu
|
||
existe, et s'il n'existe pas, nous saurons que tout est permis. Autre
|
||
exemple : posons que « si le train passe sous le tunnel avant
|
||
que j'aie compté jusqu'à dix, alors Manek est vivant. » Je vais
|
||
donc tester si le train passe sous le tunnel avant que j'aie compté
|
||
jusqu'à dix, et si c'est le cas, alors c'est que Manek est vivant. C'est
|
||
aussi simple que cela.</p>
|
||
|
||
<h3>Une condition</h3>
|
||
<p>Le shell propose deux principales façons de réaliser un test ;
|
||
ces deux méthodes sont équivalentes :</p>
|
||
|
||
<ul>
|
||
<li> <code>test <em>expression</em></code></li>
|
||
<li> <code>[ <em>expression</em> ]</code></li>
|
||
</ul>
|
||
|
||
<p>
|
||
Les deux commandes suivantes reviennent donc au même :</p>
|
||
|
||
<pre>
|
||
<span class="prompt">clipper ~ $</span> <strong>test -f foo</strong> || echo "Le fichier foo n'existe pas."
|
||
Le fichier foo n'existe pas.
|
||
<span class="prompt">clipper ~ $</span> <strong>[ -f foo ]</strong> || echo "Le fichier foo n'existe pas."
|
||
Le fichier foo n'existe pas.
|
||
</pre>
|
||
|
||
|
||
<h3>Code de retour d'un test</h3>
|
||
<p>Un test renvoie un <em>code de retour</em>. <strong>Un code de retour
|
||
est un nombre (0 ou autre), qui correspond à une réponse de
|
||
type « vrai » ou « faux »</strong>. C'est ce code de
|
||
retour qui permet la manipulation des tests dans des structures de
|
||
contrôle comme <code>if</code>, etc. </p>
|
||
|
||
<p>
|
||
Le code de retour 0 correspond à la réponse
|
||
« vrai ». Pour répondre « faux », le programme
|
||
répond... autre chose (ce peut être 1, 2, -1 ou autre).
|
||
</p>
|
||
|
||
<p>Par exemple, un pilote de Formule 1 utilise le programme
|
||
suivant :</p>
|
||
|
||
<pre>
|
||
while [[ "$couleur_du_feu" != "vert" ]]
|
||
do attendre
|
||
done
|
||
|
||
démarrer_en_trombe
|
||
</pre>
|
||
|
||
|
||
<h2>Les opérateurs</h2>
|
||
|
||
<h3>Opérateurs logiques</h3>
|
||
|
||
<h4>Non : l'opérateur « <code>!</code> »</h4>
|
||
|
||
<p><strong>L'opérateur logique « non » inverse le code de
|
||
retour d'une commande</strong>, c'est-à-dire renvoie vrai si elle
|
||
renvoie faux, et vice versa. </p>
|
||
|
||
<p>On utilise cet opérateur en précédant une condition d'un point
|
||
d'exclamation (« ! »). </p>
|
||
|
||
|
||
<h5>Comparaison de plusieurs combinaisons d'opérateurs</h5>
|
||
|
||
<p>Pour illustrer l'usage de cet opérateur, voici quatre cas de figure
|
||
différents :</p>
|
||
|
||
<pre>
|
||
# Premier cas
|
||
[ <strong>-f</strong> foo ] <strong>&&</strong> echo "Le fichier foo existe."
|
||
</pre>
|
||
|
||
<p class="continue">Dans l'exemple précédent, le shell teste si le
|
||
fichier <code>foo</code> existe. Comme il n'existe pas, le code de
|
||
retour de ce test est 0. Or, l'opérateur « && »
|
||
n'exécute ce qui suit que si le code de retour est 1. Comme ce
|
||
n'est pas le cas, les commandes ne sont pas exécutées.</p>
|
||
|
||
<pre>
|
||
# Deuxième cas
|
||
[ <strong>-f</strong> foo ] <strong>||</strong> echo "Le fichier foo n'existe pas."
|
||
Le fichier foo n'existe pas.
|
||
</pre>
|
||
|
||
<p class="continue">Dans cet exemple, l'opérateur n'est plus
|
||
« && » mais « || ». Les commandes ne
|
||
s'exécutent que si le code de retour vaut 0 ; comme c'est le cas,
|
||
elles sont exécutées.</p>
|
||
|
||
<pre>
|
||
# Troisième cas
|
||
[ <strong>! -f</strong> foo ] <strong>&&</strong> echo "Le fichier foo n'existe pas."
|
||
Le fichier foo n'existe pas.
|
||
</pre>
|
||
|
||
<p class="continue">Ici, l'opérateur est de nouveau
|
||
« && » ; mais contrairement aux deux exemples
|
||
précédents, le test n'est plus <code>[ -f foo ]</code>
|
||
mais <code>[ ! -f foo ]</code>. Par conséquent, le
|
||
code de retour est 1, et les commandes sont exécutées.</p>
|
||
|
||
<pre>
|
||
# Quatrième cas
|
||
[ <strong>! -f</strong> foo ] <strong>||</strong> echo "Le fichier foo existe."
|
||
</pre>
|
||
|
||
<p class="continue">Voici la dernière combinaison possible. Le code de
|
||
retour est 1, mais il fallait 0 pour que les commandes soient
|
||
exécutées. </p>
|
||
|
||
|
||
|
||
<p>Ces quatre exemples correspondent aux énoncés suivants :</p>
|
||
|
||
<ul>
|
||
<li> <em>s'il est vrai que <code>foo</code> existe</em>, alors il faut
|
||
écrire : « Le fichier foo existe. ».</li>
|
||
|
||
<li> <em>s'il n'est pas vrai que <code>foo</code> existe</em>, alors il
|
||
faut écrire : « Le fichier foo n'existe pas. ».</li>
|
||
|
||
<li> <em>s'il est vrai que <code>foo</code> n'existe pas</em>, alors il
|
||
faut écrire : « Le fichier foo n'existe pas. ».</li>
|
||
|
||
<li> <em>s'il n'est pas vrai que <code>foo</code> n'existe pas</em>,
|
||
alors il faut écrire : « Le fichier foo existe. ».</li>
|
||
</ul>
|
||
|
||
|
||
<h5>Reformulation avec <code>if</code></h5>
|
||
|
||
<p>Dans un script, outre la formulation précédente, on pourra
|
||
écrire :</p>
|
||
|
||
<pre>
|
||
# Premier cas
|
||
if [ -f foo ]
|
||
then echo "Le fichier foo existe."
|
||
else continue
|
||
fi
|
||
|
||
# Deuxième cas
|
||
if [ -f foo ]
|
||
then continue
|
||
else echo "Le fichier foo n'existe pas."
|
||
fi
|
||
|
||
# Troisième cas
|
||
if [ ! -f foo ]
|
||
then echo "Le fichier foo n'existe pas."
|
||
else continue
|
||
fi
|
||
|
||
# Quatrième cas
|
||
if [ ! -f foo ]
|
||
then continue
|
||
else echo "Le fichier foo existe."
|
||
fi
|
||
</pre>
|
||
|
||
|
||
<h4>Et : l'opérateur « <code>-a</code> »</h4>
|
||
<p>L'opérateur « et » renvoie 1 (vrai) si et seulement si
|
||
les différentes conditions sont toutes réalisées ; si au moins
|
||
l'une d'entre elles ne l'est pas, le code de retour est 0
|
||
(faux). On note cet opérateur en insérant « -a » entre les
|
||
différentes conditions. Exemples : </p>
|
||
|
||
<pre>
|
||
touch foo # donc foo existe
|
||
rm bar # donc bar n'existe pas
|
||
|
||
# [ -f foo ] = vrai si le fichier foo existe
|
||
# [ ! -f bar ] = vrai si bar n'existe pas
|
||
|
||
# à n'exécuter que si foo existe ET que bar n'existe pas.
|
||
[ -f foo <strong>-a</strong> ! -f bar ] &&
|
||
mv foo bar
|
||
</pre>
|
||
|
||
<p class="continue">Autres formulations possibles :
|
||
</p>
|
||
|
||
<pre>
|
||
test -f foo -a ! -f bar
|
||
[ -f foo ] -a [ ! -f bar ]
|
||
[[ -f foo && ! -f bar ]]
|
||
</pre>
|
||
|
||
<p><strong>Si vous débutez, vous n'êtes pas tenu de retenir par
|
||
cœur toutes les combinaisons possibles. Sachez simplement les
|
||
reconnaître</strong> si vous les lisez quelque part ; et pour vos
|
||
propres scripts, vous il vous suffit de savoir bien manipuler la syntaxe
|
||
qui vous paraît la plus lisible.</p>
|
||
|
||
|
||
<h4>Ou : l'opérateur « <code>-o</code> »</h4>
|
||
<p>Pour réaliser la condition de l'opérateur « ou », il suffit
|
||
qu'une seule des conditions qu'il rassemble soit vraie : </p>
|
||
|
||
<ul>
|
||
<li> si <em>toutes</em> les conditions sont rassemblées, la condition
|
||
d'ensemble l'est aussi ;</li>
|
||
|
||
<li> si <em>une partie seulement</em> de ces conditions est rassemblée,
|
||
la condition d'ensemble l'est aussi ;</li>
|
||
|
||
<li> si <em>aucune</em> des conditions incluses n'est remplie, la
|
||
condition d'ensemble ne l'est pas non plus.</li>
|
||
</ul>
|
||
|
||
<p>Exemple :</p>
|
||
|
||
<pre>
|
||
if [[ "$fichier" == "fichier_interdit" -o ! -f "$fichier" ]]
|
||
then echo "Je ne veux pas lire $fichier ou bien il n'existe pas."
|
||
fi
|
||
</pre>
|
||
|
||
<ul>
|
||
<li> si <code>$fichier</code> vaut
|
||
<code>"fichier_interdit"</code>, il n'est pas lu ;</li>
|
||
|
||
<li> si <code>$fichier</code> n'existe pas, il n'est pas lu ;</li>
|
||
|
||
<li> si <code>$fichier</code> vaut
|
||
<code>"fichier_interdit"</code> et qu'en plus il n'existe pas,
|
||
il n'est pas lu ;</li>
|
||
|
||
<li> si <code>$fichier</code> ne vaut pas
|
||
<code>"fichier_interdit"</code> et qu'il existe bien, il est
|
||
lu.</li> </ul>
|
||
|
||
<h3>Opérateurs arithmétiques</h3>
|
||
|
||
<p>
|
||
Le shell permet d'opérer des calculs arithmétiques, même s'il est moins
|
||
puissant que d'autres langages (Perl, Scheme, C, etc.) pour cela.
|
||
</p>
|
||
|
||
<p>
|
||
Les opérateurs sont les suivants :
|
||
</p>
|
||
|
||
<ul>
|
||
<li> <code>-eq</code> (<i>equal</i>) : « égal à » (signe
|
||
« = ») ;</li>
|
||
|
||
<li> <code>-ne</code> (<i>not equal</i>) : « différent
|
||
de » (signe « ≠ ») ;</li>
|
||
|
||
<li> <code>-gt</code> (<i>greater than</i>) : « strictement
|
||
supérieur à » (signe « > ») ;</li>
|
||
|
||
<li> <code>-lt</code> (<i>lesser than</i>) : « strictement
|
||
inférieur à » (signe « < ») ;</li>
|
||
|
||
<li> <code>-ge</code> (<i>greater or equal</i>) : « supérieur
|
||
ou égal à » (signe « ≥ ») ;</li>
|
||
|
||
<li> <code>-le</code> (<i>lesser or equal</i>) : « inférieur
|
||
ou égal à » (signe « ≤ ») ;</li>
|
||
</ul>
|
||
|
||
<p>
|
||
On utilise ces opérateurs entre deux nombres ou variables
|
||
numériques. Par exemple :
|
||
</p>
|
||
|
||
<pre>
|
||
#!/bin/sh
|
||
if test 2 -lt 3
|
||
then echo "C'est normal."
|
||
fi
|
||
|
||
if test 2 -gt 3
|
||
then echo "C'est absurde."
|
||
fi
|
||
|
||
petit=2
|
||
grand=3
|
||
|
||
if test $petit -ne 3
|
||
then echo "C'est normal."
|
||
fi
|
||
|
||
if test 2 -eq $grand
|
||
then echo "C'est absurde."
|
||
fi
|
||
</pre>
|
||
|
||
<p class="continue">
|
||
Si vous exécutez ce programme, vous obtenez :
|
||
</p>
|
||
|
||
<pre>
|
||
C'est normal.
|
||
C'est normal.
|
||
</pre>
|
||
|
||
|
||
<h3>Opérateurs sur les fichiers</h3>
|
||
|
||
<p>
|
||
Une grande partie de la puissance du shell se déploie dans sa faculté de
|
||
manipuler des fichiers.
|
||
</p>
|
||
|
||
<p>
|
||
Les principaux opérateurs disponibles sont :
|
||
</p>
|
||
|
||
<ul>
|
||
<li> nature du fichier :
|
||
<ul>
|
||
<li> <code>-e</code> (<i>exists</i>) : vérifie l'existence d'un
|
||
fichier ;</li>
|
||
|
||
<li> <code>-f</code> (<i>file</i>) : vérifie l'existence d'un
|
||
fichier, et le fait qu'il s'agisse bien d'un fichier au sens
|
||
strict ;</li>
|
||
|
||
<li> <code>-d</code> (<i>directory</i>) : vérifie l'existence d'un
|
||
répertoire ;</li>
|
||
|
||
<li> <code>-L</code> (<i>link</i>) : vérifie si le fichier est un
|
||
lien symbolique ;</li>
|
||
|
||
</ul></li>
|
||
|
||
<li>attributs du fichier :
|
||
<ul>
|
||
<li> <code>-s</code> (<i>size</i>) : vérifie qu'un fichier n'est
|
||
pas vide ;</li>
|
||
</ul></li>
|
||
|
||
<li>droits sur le fichier :
|
||
<ul>
|
||
<li> <code>-r</code> (<i>readable</i>) : vérifie si un fichier peut
|
||
être lu ;</li>
|
||
|
||
<li> <code>-w</code> (<i>writable</i>) : vérifie si un fichier peut
|
||
être écrit ou modifié ;</li>
|
||
|
||
<li> <code>-x</code> (<i>writable</i>) : vérifie si un fichier peut
|
||
être exécuté ;</li>
|
||
</ul></li>
|
||
|
||
<li>comparaison de fichiers :
|
||
<ul>
|
||
<li> <code>-nt</code> (<i>newer than</i>) : vérifie si un fichier
|
||
est plus récent qu'un autre ;</li>
|
||
|
||
<li> <code>-ot</code> (<i>older than</i>) : vérifie si un fichier
|
||
est plus ancien qu'un autre.</li>
|
||
</ul>
|
||
</li>
|
||
|
||
</ul>
|
||
|
||
<p>Exemple :</p>
|
||
|
||
<pre>
|
||
#!/bin/sh
|
||
|
||
if test -e ~/.emacs
|
||
then echo "~/.emacs existe."
|
||
else echo "~/.emacs n'existe pas."
|
||
fi
|
||
|
||
if test -d ~/.emacs
|
||
then echo "~/.emacs est un répertoire."
|
||
else echo "~/.emacs n'est pas un répertoire."
|
||
fi
|
||
|
||
if test -f ~/.emacs
|
||
then echo "~/.emacs est un fichier."
|
||
else echo "~/.emacs n'est pas un fichier."
|
||
fi
|
||
|
||
if test ~/.vimrc -nt ~/.emacs
|
||
then "~/.vimrc est plus récent que ~/.emacs."
|
||
fi
|
||
</pre>
|
||
|
||
|
||
<div class="metainformation">
|
||
Auteur : Baptiste Mélès.
|
||
Dernière modification le <date value="$Date: 2005-09-07 23:00:05 $" />.
|
||
</div>
|
||
|
||
</body>
|
||
</html>
|