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

467 lines
12 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>Scripts</title>
</head>
<body>
<h1><a name="programmation">Programmation de scripts en shell</a></h1>
<p>
Un shell, quel qu'il soit, peut ex<65>cuter des commandes prises dans un
fichier. Un fichier contenant des commandes pour le shell est appel<65> un
<em>script</em>. C'est en fait un <em>programme</em> <20>crit <em>dans le
langage du shell</em>. Ce langage comprend non seulement les commandes que
nous avons d<>j<EFBFBD> vues, mais aussi des structures de contr<74>le
(constructions conditionnelles et boucles).
</p>
<p>
Pour la programmation du shell, nous allons utiliser le shell
<code>sh</code>, qui est le plus r<>pandu et standard. Ce que nous avons
vu jusqu'ici s'applique aussi bien <20> <code>sh</code> qu'<27>
<code>zsh</code> et aussi <20> <code>csh</code>, <20> l'exception de
<code>setenv</code> et de certaines redirections signal<61>es. </p>
<h2>Cr<43>er un script</h2>
<h3>Rendre un script ex<65>cutable</h3>
<p> Pour <20>tre un script, un fichier doit commencer par la ligne: </p>
<pre>#!/bin/sh</pre>
<p>
Il doit aussi avoir <20>tre ex<65>cutable (bit <code>x</code>). Le
<code>#!/bin/sh</code> sur la premi<6D>re ligne indique que ce script doit <20>tre
ex<EFBFBD>cut<EFBFBD> par le shell <code>sh</code> dont on indique le chemin
d'acc<63>s. Pour rendre un fichier ex<65>cutable, tapez&nbsp;:
</p>
<pre><span class="prompt">chaland ~</span> chmod u+x fichier
</pre>
<p class="continue">
(pour en savoir plus sur les droits attach<63>s <20> un fichier, consultez la
page sur <a href="droits.html">les droits d'acc<63>s</a>).
</p>
<h3>Le chemin d'une commande</h3>
<p>
Pour comprendre ce qui suit, vous devez savoir ce qu'est le
<code>PATH</code>. Si ce n'est pas le cas, lisez la <a
href="index.html">page principale sur le shell</a>.
</p>
<p>
Quand vous ex<65>cutez un script, vous pouvez vous trouver <20>
n'importe quel endroit de l'arborescence de vos r<>pertoires. Si le
r<EFBFBD>pertoire courant ne se situe pas dans votre <code>PATH</code> et
que vous voulez ex<65>cuter un programme qui s'y trouve, vous ne pouvez
pas taper&nbsp;:
</p>
<pre>
<span class="prompt">clipper ~</span> commande
</pre>
<p class="continue">car si le r<>pertoire courant n'est pas dans le
<code>PATH</code>, le shell n'ira pas y chercher
<code>commande</code>. </p>
<p>
Vous recevrez donc un message comme&nbsp;:
</p>
<pre>
<span class="prompt">clipper ~</span> commande
zsh: command not found: commande</pre>
<h4>Sp<53>cifier le chemin d'une commande</h4>
<p>
Pour que le shell comprenne o<> chercher votre commande, il faut donc
sp<EFBFBD>cifier l'emplacement de la commande en donnant son chemin, qu'il
soit absolu&nbsp;:
</p>
<pre>
<span class="prompt">clipper ~</span> /home/toto/repertoire/courant/commande
</pre>
<p class="continue">ou relatif&nbsp;: </p>
<pre>
<span class="prompt">clipper ~</span> repertoire/courant/commande
</pre>
<p class="continue">ou encore sous la forme&nbsp;: </p>
<pre>
<span class="prompt">clipper ~/repertoire/courant</span> ./commande
</pre>
<h4>Le r<>pertoire <code>~/bin</code></h4>
<p>
Il y a un certain nombre de commandes que l'on peut vouloir utiliser
depuis n'importe quel r<>pertoire. Dans ce cas, il est fastidieux de&nbsp;:
</p>
<ul>
<li> devoir se rappeler dans quel r<>pertoire se trouve chacune
d'entre elles&nbsp;;</li>
<li> devoir taper <20> chaque fois le chemin de la commande.</li>
</ul>
<p>Il suffit donc de mettre tous vos scripts dans un m<>me
r<EFBFBD>pertoire, et de mettre ce r<>pertoire dans le
<code>PATH</code>. Par convention, ce r<>pertoire s'appelle
<code>bin</code> et se place dans votre r<>pertoire personnel. Si
votre r<>pertoire personnel est <code>/home/toto</code>, ce
r<EFBFBD>pertoire sera donc <code>/home/toto/bin</code>. </p>
<p>
Commencez donc par cr<63>er ce r<>pertoire&nbsp;:
</p>
<pre>
<span class="prompt">clipper ~</span> mkdir bin
</pre>
<p>
Ensuite, v<>rifiez qu'il soit bien dans votre <code>PATH</code>&nbsp;:
</p>
<pre>
<span class="prompt">clipper ~</span> echo $PATH
</pre>
<p class="continue">Si vous voyez par exemple <code>$HOME/bin</code>
dans votre <code>PATH</code>, alors c'est bon, tous les fichiers
ex<EFBFBD>cutables situ<74>s dans ce r<>pertoire seront accessibles depuis
n'importe quel r<>pertoire.
</p>
<p>
Si ce n'est pas le cas, il faut ajouter ce r<>pertoire au
<code>PATH</code>. Pour cela, ajoutez dans le fichier de configuration
de votre shell, par exemple le fichier <code>.zshrc</code>, la
ligne&nbsp;:
</p>
<pre>PATH=$PATH:$HOME/bin</pre>
<p class="continue">Cette ligne indique que la prochaine fois que vous
ouvrirez votre shell, le r<>pertoire <code>bin</code> figurera dans
votre <code>PATH</code>.
</p>
<h2>Principes g<>n<EFBFBD>raux des scripts shell</h2>
<h3>Une succession de commandes</h3>
<p> Si vous manipulez d<>j<EFBFBD> le shell en ligne de commande, vous
pouvez commencer vos premiers scripts. Un script shell est en effet
avant tout une <strong>succession de commandes</strong>.
</p>
<p> Par exemple, si vous avez coutume de taper successivement, quand
vous vous loguez <20> l'ENS&nbsp;:
</p>
<pre>
<span class="prompt">clipper ~</span> mozilla &amp;
<span class="prompt">clipper ~</span> mutt
</pre>
<p class="continue">vous pouvez vous cr<63>er le script suivant dans le
fichier <code>~/bin/amorce</code>&nbsp;:</p>
<pre>
#!/bin/sh
mozilla &amp;
mutt
</pre>
<p>Ainsi, d<>s que vous vous connectez, vous pouvez taper
<code>amorce</code> dans le shell, et vos commandes s'ex<65>cuteront
automatiquement. </p>
<h3>Commentaires</h3>
<p>
Presque tous les langages informatiques autorisent d'ins<6E>rer des
commentaires&nbsp;; le shell n'<27>chappe pas <20> la r<>gle. Pour
cela, il suffit de faire pr<70>c<EFBFBD>der chaque ligne de commentaire du
caract<EFBFBD>re <20>&nbsp;#&nbsp;<3B>. Exemple&nbsp;:
</p>
<pre>
#!/bin/sh
# Tout ce que j'<27>cris ici ne sera pas lu.
echo &quot;Ce que je tape ici sera lu.&quot;
</pre>
<p>
Les lignes blanches ne sont pas interpr<70>t<EFBFBD>es non
plus. N'h<>sitez donc surtout pas <20> espacer votre script, les
lignes blanches ne consomment presque rien en termes d'espace disque, ce
n'est donc pas une ressource rare.
</p>
<h3>L'imp<6D>ratif de lisibilit<69></h3>
<p>
Pourquoi espacer son script&nbsp;? Pourquoi ins<6E>rer des
commentaires&nbsp;? Pour une seule et m<>me raison&nbsp;:
<strong>votre script doit <20>tre lisible</strong>. Pourquoi <20>tre
lisible&nbsp;? </p>
<p> D'abord, pour autrui&nbsp;: si d'autres gens lisent votre script, il
doit <20>tre intelligible, et les passages complexes doivent <20>tre
explicit<EFBFBD>s par des commentaires.</p>
<p> Ensuite, pour vous-m<>me&nbsp;; au moment o<> vous <20>crivez un
script, vous comprenez tout, naturellement&nbsp;; mais si vous le
relisez dans quelques mois, voire quelques ann<6E>es, les passages
obscurs risqueront d'<27>tre incompr<70>hensibles, ce qui est
particuli<EFBFBD>rement p<>nible quand on essaye de <em>d<>buguer</em>
un programme, c'est-<2D>-dire d'en corriger les erreurs.
</p>
2005-06-03 15:56:21 +02:00
<h2>Un script qui parle&nbsp;: la commande <code>echo</code></h2>
<p>
2005-06-03 15:56:21 +02:00
Maintenant que vous savez comment on peut ex<65>cuter un script, il s'agit
de le remplir... Commen<65>ons par ce qu'il y a de plus simple&nbsp;:
afficher du texte.
</p>
2005-06-03 15:56:21 +02:00
<h3>Hello World&nbsp;!</h3>
<p>
2005-06-03 15:56:21 +02:00
Traditionnellement, on commence par faire un programme qui affiche
simplement la ligne <20>&nbsp;Hello world&nbsp;<3B> (ce qui signifie en
anglais&nbsp;: bonjour au monde entier). Faites donc un fichier
<code>helloworld</code> contenant les lignes suivantes&nbsp;:
</p>
2005-06-03 15:56:21 +02:00
<pre>
#!/bin/sh
2005-06-03 15:56:21 +02:00
# Fichier &quot;helloworld&quot;
echo &quot;Hello world&quot;
</pre>
<p>
2005-06-03 15:56:21 +02:00
Ex<EFBFBD>cutez ensuite ce programme, par exemple en tapant, dans le r<>pertoire
o<EFBFBD> il se trouve&nbsp;:
</p>
<pre><span class="prompt">clipper ~ $</span> ./helloworld
Hello world</pre>
<p>
2005-06-03 15:56:21 +02:00
<EFBFBD>a y est, vous avez cr<63><72> votre premier programme&nbsp;! Lancez-le autant
de vous que vous voulez, vous avez bien m<>rit<69> d'<27>tre fier de vous.
</p>
2005-06-03 15:56:21 +02:00
<p>
Exercice&nbsp;: francisez ce script.
</p>
2005-06-03 15:56:21 +02:00
<h3>La commande <code>echo</code></h3>
<p>
2005-06-03 15:56:21 +02:00
La commande <code>echo</code> sert <20> afficher du texte sur la sortie
standard (pour savoir ce qu'est la sortie standard, consultez la page
sur les <a href="entreesortie.html">entr<74>es et sorties</a>). Chaque
ligne de texte est <20>crite sur une ligne <20> part. Exemple&nbsp;:
</p>
2005-06-03 15:56:21 +02:00
<pre>
#!/bin/sh
# Fichier &quot;bonjour&quot;
2005-06-03 15:56:21 +02:00
echo &quot;Bonjour... &quot;
echo &quot;Comment allez-vous ?&quot;
</pre>
2005-06-03 15:56:21 +02:00
<p class="continue">affiche les lignes suivantes&nbsp;:</p>
2005-06-03 15:56:21 +02:00
<pre>
Bonjour...
Comment allez-vous ?
</pre>
2005-06-03 15:56:21 +02:00
<p class="continue">et non&nbsp;:</p>
2005-06-03 15:56:21 +02:00
<pre>
Bonjour... Comment allez-vous ?
</pre>
2005-06-03 15:56:21 +02:00
<h4>Annuler le retour chariot</h4>
<p>
2005-06-03 15:56:21 +02:00
Si vous voulez annuler le retour chariot qui a lieu par d<>faut <20> la fin
de toute commande <code>echo</code>, il faut utiliser l'option
<code>-n</code>. Le programme sera alors&nbsp;:
</p>
2005-06-03 15:56:21 +02:00
<pre>
#!/bin/sh
2005-06-03 15:56:21 +02:00
echo -n &quot;Bonjour...&quot;
echo &quot;Comment allez-vous ?&quot;
</pre>
<p class="continue">
Alors seulement, vous pourrez avoir&nbsp;:
</p>
2005-06-03 15:56:21 +02:00
<pre>
Bonjour... Comment allez-vous ?
</pre>
2005-06-03 15:56:21 +02:00
<h4>Citer des variables</h4>
2005-06-03 15:56:21 +02:00
<p>Faisons mieux encore&nbsp;: votre script va citer des variables. Pour
savoir ce que sont des variables, allez voir la page sur les <a
href="variable.html">variables</a>.</p>
2005-06-03 15:56:21 +02:00
<p>La variable <code>USER</code> contient le login de
l'utilisateur&nbsp;; la variable <code>PWD</code> (pour <em>print
working directory</em>) affiche le r<>pertoire courant. Faisons donc le
script suivant&nbsp;:</p>
2005-06-03 15:56:21 +02:00
<pre>
#/bin/sh
# Fichier &quot;mon-pwd&quot;
2005-06-03 15:56:21 +02:00
echo &quot;Bonjour $USER...&quot;
echo &quot;Tu es actuellement dans le r<>pertoire $PWD.&quot;
</pre>
2005-06-03 15:56:21 +02:00
<p>Comme vous pouvez le remarquer, pour citer le contenu d'une variable,
on ajoute le signe dollar ($) devant son nom.</p>
2005-06-03 15:56:21 +02:00
<h2>Un script qui <20>coute&nbsp;: la commande <code>read</code></h2>
2005-06-03 15:56:21 +02:00
<p>Parler c'est bien, <20>couter c'est mieux. Jusqu'ici, votre programme
est capable de parler, de dire bonjour, mais il n'est m<>me pas capable
de vous appeler par votre nom, tout juste par votre login, ce qui n'est
pas tr<74>s intime...</p>
<p>
2005-06-03 15:56:21 +02:00
Nous allons donc lui donner la facult<6C> d'<27>couter, gr<67>ce <20> la commande
<code>read</code>. Prenons le script suivant&nbsp;:
</p>
<pre>
2005-06-03 15:56:21 +02:00
#!/bin/sh
# Fichier &quot;mon-nom&quot;
2005-06-03 15:56:21 +02:00
echo &quot;Bonjour... Comment vous-appelez-vous ?&quot;
read nom
echo &quot;Je vous souhaite, $nom, de passer une bonne journ<72>e.&quot;
</pre>
2005-06-03 15:56:21 +02:00
<p>Vous connaissez d<>j<EFBFBD> la commande <code>echo</code>. La commande
<code>read</code> permet de lire des variables. Si vous ex<65>cutez ce
script, apr<70>s avoir affich<63> la ligne </p>
2005-06-03 15:56:21 +02:00
<pre>
Bonjour... Comment vous-appelez-vous ?
</pre>
2005-06-03 15:56:21 +02:00
<p class="continue">le shell va attendre que vous tapiez votre
nom. Tapez par exemple <code>Toto</code>, puis appuyez sur Entr<74>e, et
vous verrez&nbsp;:</p>
<pre>
Bonjour... Comment vous-appelez-vous ?
<em>Toto</em>
Je vous souhaite, Toto, de passer une bonne journ<72>e.</pre>
<div class="attention">
La commande <code>read</code> doit <20>tre suivie du seul nom de la
variable, <strong>non pr<70>c<EFBFBD>d<EFBFBD> du signe dollar</strong>. <em>Le signe
dollar ne doit pr<70>c<EFBFBD>der le nom de la variable que lorsque l'on cite son
contenu.</em>
</div>
<h3>Lire plusieurs variables</h3>
<p>
2005-06-03 15:56:21 +02:00
La commande <code>read</code> permet <20>galement de lire plusieurs
variables. Il suffit pour cela d'indiquer <20> la suite les noms des
diff<EFBFBD>rentes variables. Exemple&nbsp;:
</p>
<pre>
2005-06-03 15:56:21 +02:00
#!/bin/sh
# Fichier &quot;administration&quot;
echo &quot;<3B>crivez votre nom puis votre pr<70>nom :&quot;
read nom prenom
echo &quot;Nom : $nom&quot;
echo &quot;Pr<50>nom : $prenom&quot;
</pre>
<p>Vous aurez&nbsp;:</p>
<pre>
<EFBFBD>crivez votre nom puis votre pr<70>nom :
<em>Hugo Victor</em>
Nom : Hugo
Pr<EFBFBD>nom : Victor
</pre>
2005-06-03 15:56:21 +02:00
<h3>Appuyer sur Entr<74>e pour continuer</h3>
<p>Nous avons vu comment utiliser <code>read</code> avec un seul
argument et avec plusieurs arguments&nbsp;; il reste <20> voir l'usage de
<code>read</code> <em>sans</em> argument. Oui, c'est possible&nbsp;!
Cela <20>quivaut simplement <20> attendre un r<>action de l'utilisateur, mais
sans m<>moriser ce qu'il tape.</p>
<p> Concr<63>tement, cela est tr<74>s utile apr<70>s un message <20>&nbsp;Appuyez
sur Entr<74>e pour continuer.&nbsp;<3B> Exemple&nbsp;:</p>
<pre>
#!/bin/sh
# Fichier &quot;continuer&quot;
echo &quot;Quelle est la diff<66>rence entre un canard ?&quot;
echo &quot;(Appuyez sur Entr<74>e pour avoir la r<>ponse)&quot;
read
echo &quot;Les pattes, surtout la gauche.&quot;
</pre>
<div class="metainformation">
2005-06-03 15:56:21 +02:00
Auteur&nbsp;: Baptiste M<>l<EFBFBD>s.
Derni<EFBFBD>re modification le <date value="$Date: 2005-06-03 13:56:22 $" />.
</div>
</body>
</html>