tuteurs.ens.fr/unix/shell/test.tml

425 lines
11 KiB
Text
Raw Normal View History

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