Bap: Tests et calcul arithmétique en shell

This commit is contained in:
meles 2005-09-07 10:03:49 +00:00
parent 65e2de4b07
commit 96a1692382
4 changed files with 470 additions and 5 deletions

View file

@ -90,6 +90,18 @@ Vous venez de terminer ce programme, et vous
fonctionne comme vous le voulez.
</p>
<div class="encadre">
Soyons honnêtes&nbsp;: cet exemple est un peu tiré par les cheveux, car
il existe une commande très simple pour faire cela&nbsp;:
<pre>
rm -i *.aux *.log
</pre>
Mais ici, cet exemple <em>à la limite</em> est là pour illustrer d'une
façon simple l'intérêt des fonctions... Disons alors que cet exemple
permet de donner une version francisée de la commande
<code>rm&nbsp;-i&nbsp;*.aux&nbsp;*.log</code>&nbsp;!
</div>
<h3>Problèmes des programmes sans fonction</h3>
@ -131,7 +143,7 @@ L'utilisation des fonctions se fait en deux moments&nbsp;:
<ol>
<li> d'abord, il faut <strong>définir la fonction</strong>&nbsp;: vous
décrivez quelle série de commandes il faudra exécuter lrosque l'on
décrivez quelle série de commandes il faudra exécuter lorsque l'on
appellera la fonction&nbsp;;</li>
<li> ensuite, il faut <strong>appeler la fonction</strong> à chaque
@ -405,7 +417,7 @@ complexes.
<div class="metainformation">
Auteur : Baptiste Mélès.
Dernière modification le <date value="$Date: 2005-09-07 09:02:15 $" />.
Dernière modification le <date value="$Date: 2005-09-07 10:03:49 $" />.
</div>
</body>

View file

@ -80,7 +80,10 @@ redirection</a>&nbsp;;</li>
<li> <a href="test.html">test et calcul arithmétique</a>&nbsp;;</li>
<li> <a href="boucle.html">boucles et structures de contrôle</a>.</li>
<li> <a href="boucle.html">boucles et structures de
contrôle</a>&nbsp;;</li>
<li> <a href="fonction.html">définir et appeler des fonctions</a>.</li>
</ul>
@ -88,7 +91,7 @@ redirection</a>&nbsp;;</li>
Basé sur un polycopié de Roberto Di Cosmo, Xavier Leroy et Damien
Doligez.
Modifications&nbsp;: Nicolas George, Baptiste Mélès.
Dernière modification le <date value="$Date: 2005-07-05 07:18:06 $"
Dernière modification le <date value="$Date: 2005-09-07 10:03:53 $"
/>.
</div>

View file

@ -604,10 +604,39 @@ read
echo &quot;Les pattes, surtout la gauche.&quot;
</pre>
<h2>Poursuivre l'apprentissage de la programmation shell</h2>
<p>
Vous connaissez maintenant les bases de la programmation en shell. Vous
avza déjà de quoi écrire de nombreux scripts qui peuvent vous faciliter
la vie de tous les jours. Pour cela, lorsque vous ressentez un besoin,
ne vous demandez pas si vous avez les connaissances requises pour écrire
un programme donné, mais plutôt <em>comment, à partir de vos
connaissances actuelles, vous pourriez le réaliser</em>.
</p>
<p>
Pour poursuivre votre apprentissage, vous pouvez passer à la lecture des
pages suivanets&nbsp;:
</p>
<ul>
<li> <a href="entreesortie.html">entrée, sortie,
redirection</a>&nbsp;;</li>
<li> <a href="test.html">test et calcul arithmétique</a>&nbsp;;</li>
<li> <a href="boucle.html">boucles et structures de
contrôle</a>&nbsp;;</li>
<li> <a href="fonction.html">définir et appeler des fonctions</a>.</li>
</ul>
<div class="metainformation">
Auteur&nbsp;: Baptiste Mélès.
Dernière modification le <date value="$Date: 2005-07-05 07:18:06 $" />.
Dernière modification le <date value="$Date: 2005-09-07 10:03:54 $" />.
</div>
</body>

421
unix/shell/test.tml Normal file
View file

@ -0,0 +1,421 @@
<?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&nbsp;?</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&nbsp;: 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&nbsp;: «&nbsp;Si Dieu n'existe
pas, alors tout est permis.&nbsp;» Nous allons ensuite tester si Dieu
existe, et s'il n'existe pas, nous saurons que tout est permis. Autre
exemple&nbsp;: posons que «&nbsp;si le train passe sous le tunnel avant
que j'aie compté jusqu'à dix, alors Manek est vivant.&nbsp;» 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 trois façons de réaliser un test&nbsp;; ces trois
méthodes sont équivalentes&nbsp;:</p>
<ul>
<li> <code>test <em>expression</em></code></li>
<li> <code>[ <em>expression</em> ]</code></li>
<li> <code>[[ <em>expression</em> ]]</code></li>
</ul>
<p>
Les trois commandes suivantes reviennent donc au même&nbsp;:</p>
<pre>
<span class="prompt">clipper ~ $</span>&nbsp;<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>&nbsp;<strong>[ -f foo ]</strong> || echo &quot;Le fichier foo n'existe pas.&quot;
Le fichier foo n'existe pas.
<span class="prompt">clipper ~ $</span>&nbsp;<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 chiffre binaire (1 ou&nbsp;0), qui correspond à une réponse de
type «&nbsp;vrai&nbsp;» ou «&nbsp;faux&nbsp;»</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>Par exemple, un pilote de Formule&nbsp;1 utilise le programme
suivant&nbsp;:</p>
<pre>
while [[ &quot;$couleur_du_feu&quot; != &quot;vert&quot; ]]
do attendre
done
démarrer_en_trombe
</pre>
<h2>Les opérateurs</h2>
<h3>Opérateurs logiques</h3>
<h4>Non&nbsp;: l'opérateur «&nbsp;<code>!</code>&nbsp;»</h4>
<p><strong>L'opérateur logique «&nbsp;non&nbsp;» 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 («&nbsp;!&nbsp;»). </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&nbsp;:</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é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&nbsp;0. Or, l'opérateur «&nbsp;&amp;&amp;&nbsp;»
n'exécute ce qui suit que si le code de retour est&nbsp;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 &quot;Le fichier foo n'existe pas.&quot;
Le fichier foo n'existe pas.
</pre>
<p class="continue">Dans cet exemple, l'opérateur n'est plus
«&nbsp;&amp;&amp;&nbsp;» mais «&nbsp;||&nbsp;». Les commandes ne
s'exécutent que si le code de retour vaut 0&nbsp;; comme c'est le cas,
elles sont exécutées.</p>
<pre>
# Troisième cas
[ <strong>! -f</strong> foo ] <strong>&amp;&amp;</strong> echo &quot;Le fichier foo n'existe pas.
Le fichier foo n'existe pas.
</pre>
<p class="continue">Ici, l'opérateur est de nouveau
«&nbsp;&amp;&amp;&nbsp;»&nbsp;; mais contrairement aux deux exemples
précédents, le test n'est plus <code>[&nbsp;-f&nbsp;foo&nbsp;]</code>
mais <code>[&nbsp;!&nbsp;-f&nbsp;foo&nbsp;]</code>. Par conséquent, le
code de retour est&nbsp;1, et les commandes sont exécutées.</p>
<pre>
# Quatrième cas
[ <strong>! -f</strong> foo ] <strong>||</strong> echo &quot;Le fichier foo existe.
</pre>
<p class="continue">Voici la dernière combinaison possible. Le code de
retour est&nbsp;1, mais il fallait&nbsp;0 pour que les commandes soient
exécutées. </p>
<p>Ces quatre exemples correspondent aux énoncés suivants&nbsp;:</p>
<ul>
<li> <em>s'il est vrai que <code>foo</code> existe</em>, alors il faut
écrire&nbsp;: «&nbsp;Le fichier foo existe.&nbsp;».</li>
<li> <em>s'il n'est pas vrai que <code>foo</code> existe</em>, alors il
faut écrire&nbsp;: «&nbsp;Le fichier foo n'existe pas.&nbsp;».</li>
<li> <em>s'il est vrai que <code>foo</code> n'existe pas</em>, alors il
faut écrire&nbsp;: «&nbsp;Le fichier foo n'existe pas.&nbsp;».</li>
<li> <em>s'il n'est pas vrai que <code>foo</code> n'existe pas</em>,
alors il faut écrire&nbsp;: «&nbsp;Le fichier foo existe.&nbsp;».</li>
</ul>
<h5>Reformulation avec <code>if</code></h5>
<p>Dans un script, outre la formulation précédente, on pourra
écrire&nbsp;:</p>
<pre>
# Premier cas
if [ -f foo ]
then echo &quot;Le fichier foo existe.&quot;
else continue
fi
# Deuxième cas
if [ -f foo ]
then continue
else echo &quot;Le fichier foo n'existe pas.&quot;
fi
# Troisième cas
if [ ! -f foo ]
then echo &quot;Le fichier foo n'existe pas.&quot;
else continue
fi
# Quatrième cas
if [ ! -f foo ]
then continue
else echo &quot;Le fichier foo existe.&quot;
fi
</pre>
<h4>Et&nbsp;: l'opérateur «&nbsp;<code>-a</code>&nbsp;»</h4>
<p>L'opérateur «&nbsp;et&nbsp;» renvoie&nbsp;1 (vrai) si et seulement si
les différentes conditions sont toutes réalisées&nbsp;; si au moins
l'une d'entre elles ne l'est pas, le code de retour est&nbsp;0
(faux). On note cet opérateur en insérant «&nbsp;-a&nbsp;» entre les
différentes conditions. Exemples&nbsp;: </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 ] &amp;&amp;
mv foo bar
</pre>
<p class="continue">Autres formulations possibles&nbsp;:
</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'êtes pas tenu de retenir par
c&oelig;ur toutes les combinaisons possibles. Sachez simplement les
reconnaître</strong> si vous les lisez quelque part&nbsp;; 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&nbsp;: l'opérateur «&nbsp;<code>-o</code>&nbsp;»</h4>
<p>Pour réaliser la condition de l'opérateur «&nbsp;ou&nbsp;», il suffit
qu'une seule des conditions qu'il rassemble soit vraie&nbsp;: </p>
<ul>
<li> si <em>toutes</em> les conditions sont rassemblées, la condition
d'ensemble l'est aussi&nbsp;;</li>
<li> si <em>une partie seulement</em> de ces conditions est rassemblée,
la condition d'ensemble l'est aussi&nbsp;;</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&nbsp;:</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&nbsp;;</li>
<li> si <code>$fichier</code> n'existe pas, il n'est pas lu&nbsp;;</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&nbsp;;</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é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&nbsp;:
</p>
<ul>
<li> <code>-eq</code> (<i>equal</i>)&nbsp;: «&nbsp;égal à&nbsp;» (signe
«&nbsp;=&nbsp;»)&nbsp;;</li>
<li> <code>-ne</code> (<i>not equal</i>)&nbsp;: «&nbsp;différent
de&nbsp;» (signe «&nbsp;&ne;&nbsp;»)&nbsp;;</li>
<li> <code>-gt</code> (<i>greater than</i>)&nbsp;: «&nbsp;strictement
supérieur à&nbsp;» (signe «&nbsp;&gt;&nbsp;»)&nbsp;;</li>
<li> <code>-lt</code> (<i>lesser than</i>)&nbsp;: «&nbsp;strictement
inférieur à&nbsp;» (signe «&nbsp;&lt;&nbsp;»)&nbsp;;</li>
<li> <code>-ge</code> (<i>greater or equal</i>)&nbsp;: «&nbsp;supérieur
ou égal à&nbsp;» (signe «&nbsp;&ge;&nbsp;»)&nbsp;;</li>
<li> <code>-le</code> (<i>lesser or equal</i>)&nbsp;: «&nbsp;inférieur
ou égal à&nbsp;» (signe «&nbsp;&le;&nbsp;»)&nbsp;;</li>
</ul>
<p>
On utilise ces opérateurs entre deux nombres ou variables
numériques. Par exemple&nbsp;:
</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écutez ce programme, vous obtenez&nbsp;:
</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&nbsp;:
</p>
<ul>
<li> nature du fichier&nbsp;:
<ul>
<li> <code>-e</code> (<i>exists</i>)&nbsp;: vérifie l'existence d'un
fichier&nbsp;;</li>
<li> <code>-f</code> (<i>file</i>)&nbsp;: vérifie l'existence d'un
fichier, et le fait qu'il s'agisse bien d'un fichier au sens
strict&nbsp;;</li>
<li> <code>-d</code> (<i>directory</i>)&nbsp;: vérifie l'existence d'un
répertoire&nbsp;;</li>
<li> <code>-L</code> (<i>link</i>)&nbsp;: vérifie si le fichier est un
lien symbolique&nbsp;;</li>
</ul></li>
<li>attributs du fichier&nbsp;:
<ul>
<li> <code>-s</code> (<i>size</i>)&nbsp;: vérifie qu'un fichier n'est
pas vide&nbsp;;</li>
</ul></li>
<li>droits sur le fichier&nbsp;:
<ul>
<li> <code>-r</code> (<i>readable</i>)&nbsp;: vérifie si un fichier peut
être lu&nbsp;;</li>
<li> <code>-w</code> (<i>writable</i>)&nbsp;: vérifie si un fichier peut
être écrit ou modifié&nbsp;;</li>
<li> <code>-x</code> (<i>writable</i>)&nbsp;: vérifie si un fichier peut
être exécuté&nbsp;;</li>
</ul></li>
<li>comparaison de fichiers&nbsp;:
<ul>
<li> <code>-nt</code> (<i>newer than</i>)&nbsp;: vérifie si un fichier
est plus récent qu'un autre&nbsp;;</li>
<li> <code>-ot</code> (<i>older than</i>)&nbsp;: vérifie si un fichier
est plus ancien qu'un autre.</li>
</ul>
</li>
</ul>
<p>Exemple&nbsp;:</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 : Baptiste Mélès.
Dernière modification le <date value="$Date: 2005-09-07 10:03:55 $" />.
</div>
</body>
</html>