614 lines
17 KiB
XML
614 lines
17 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>Scripts</title>
|
|
</head>
|
|
<body>
|
|
|
|
<h1><a name="programmation">Programmation de scripts en shell</a></h1>
|
|
|
|
|
|
<p>
|
|
Un shell, quel qu'il soit, peut exécuter des commandes prises dans un
|
|
fichier. Un fichier contenant des commandes pour le shell est appelé un
|
|
<em>script</em>. C'est en fait un <em>programme</em> écrit <em>dans le
|
|
langage du shell</em>. Ce langage comprend non seulement les commandes que
|
|
nous avons déjà vues, mais aussi des structures de contrô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 à <code>sh</code> qu'à
|
|
<code>zsh</code> et aussi à <code>csh</code>, à l'exception de
|
|
<code>setenv</code> et de certaines redirections signalées. </p>
|
|
|
|
|
|
<h2>Créer un script</h2>
|
|
|
|
<h3>Écrire un script</h3>
|
|
<p>
|
|
Un script shell est un fichier en mode texte. C'est-à-dire que ce n'est
|
|
pas un fichier binaire, exécutable directement par la machine, mais
|
|
<strong>il doit être interprété</strong>.
|
|
</p>
|
|
|
|
<h4>L'interprétation d'un script</h4>
|
|
|
|
<p>
|
|
L'interprétation signifie que chaque commande contenue dans un script
|
|
doit être lue par un programme, appelé <em>interpréteur</em> (et non
|
|
interprète, bizarrement) ; l'interpréteur analyse chaque commande
|
|
du script et la traduit en langage machine, ce qui permet l'exécution du
|
|
script.
|
|
</p>
|
|
|
|
<p>Dans le cas des scripts shell, l'interpréteur, c'est le shell
|
|
lui-même. Dans d'autres langages, comme le Perl, l'interpréteur est un
|
|
programme indépendant du shell. </p>
|
|
|
|
|
|
<h4>L'édition d'un script</h4>
|
|
<p>Un script étant un fichier en mode texte, il doit être créé avec un
|
|
éditeur de texte. Un éditeur de texte est un programme dont la fonction
|
|
est... d'éditer du texte. Pour savoir plus à leur sujet, consultez les
|
|
pages sur les <a href="&url.tuteurs;unix/editeurs/">éditeurs</a>. </p>
|
|
|
|
<p>Mais quel éditeur choisir ?</p>
|
|
|
|
<p> Tout d'abord, il faut savoir que <strong>n'importe quel éditeur est
|
|
capable d'ouvrir et d'écrire des scripts shell</strong>, et vous pouvez
|
|
tout à fait modifier avec n'importe quel éditeur de texte ce que vous
|
|
avez écrit avec n'importe quel autre.</p>
|
|
|
|
<p>Mais il faut savoir aussi que <strong>certains éditeurs de texte sont
|
|
plus appropriés que d'autres à l'écriture de scripts shell</strong>. Par
|
|
exemple, <code>nano</code> permet d'éditer des scripts comme tout autre
|
|
éditeur, mais quand un script fait plus d'une ligne, on commence à s'y
|
|
perdre un peu. À l'inverse, <code>emacs</code> et <code>vim</code>
|
|
offrent quelques fonctionnalités qui deviennent rapidement
|
|
indispensables :</p>
|
|
|
|
<ol>
|
|
<li> l'indentation ;</li>
|
|
<li> la coloration syntaxique.</li>
|
|
</ol>
|
|
|
|
|
|
<h5>L'indentation</h5>
|
|
|
|
<p>L'indentation consiste à « aérer » votre texte selon sa
|
|
construction logique. C'est très utile, en particulier, quand on a un
|
|
script qui ressemble à ceci :</p>
|
|
|
|
<pre>
|
|
#!/bin/sh
|
|
# Fichier "vote-nir"
|
|
|
|
echo "Êtes-vous favorable au remplacement du NIR par le
|
|
VIR ?"
|
|
select opinion in Pour Contre
|
|
do
|
|
case $opinion in
|
|
# Laisser passer ceux qui répondent correctement à 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>Même (surtout) si vous ne comprenez pas ce que tout cela veut dire,
|
|
vous conviendrez que ce n'est pas très lisible. Comparez donc avec
|
|
ceci : </p>
|
|
|
|
<pre>
|
|
#!/bin/sh
|
|
# Fichier "vote-nir"
|
|
|
|
echo "Êtes-vous favorable au remplacement du NIR par le
|
|
VIR ?"
|
|
select opinion in Pour Contre
|
|
do
|
|
case $opinion in
|
|
# Laisser passer ceux qui répondent correctement à 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>Les deux scripts sont interprétés exactement de la même façon :
|
|
l'interpréteur ignore les espaces et les lignes vides. Mais avec
|
|
l'indentation, on perçoit immédiatement (en tout cas, beaucoup plus
|
|
vite) la structure logique du script.</p>
|
|
|
|
|
|
<h5>La coloration syntaxique</h5>
|
|
<p>Les éditeurs comme <code>emacs</code> et <code>vim</code> analysent
|
|
automatiquement le statut des différents mots et symboles que vous tapez
|
|
et les colorent logiquement. Par exemple, avec emacs, vous pouvez
|
|
avoir :</p>
|
|
|
|
<ul>
|
|
<li> les commentaires en rouge ;</li>
|
|
<li> les noms de commande en bleu foncé ;</li>
|
|
<li> les noms d'arguments en vert ;</li>
|
|
<li> les noms de variables en jaune ;</li>
|
|
<li> les instructions liées aux boucles en bleu clair ;</li>
|
|
<li> etc.</li>
|
|
</ul>
|
|
|
|
<p>Ça n'a l'air de rien, dit comme cela, mais comparez vous-même et vous
|
|
verrez que ces outils sont indispensables, et que l'on y gagne au moins
|
|
la moitié du temps d'écriture et de débugage.</p>
|
|
|
|
<h5>Apprendre <code>emacs</code> ou <code>vim</code></h5>
|
|
|
|
<p>Apprenez donc, si ce n'est pas déjà le cas, les commandes de base
|
|
d'emacs ou de vim, ce sont des outils quasi incontournables au
|
|
programmeur shell, surtout débutant.</p>
|
|
|
|
<p> Heureusement, les tuteurs vous ont concocté des pages
|
|
d'initiation : le <a
|
|
href="&url.tuteurs;unix/editeurs/emacs.html">tutorial
|
|
<code>emacs</code></a> et le <a
|
|
href="&url.tuteurs;unix/editeurs/vim.html">tutorial
|
|
<code>vim</code></a>.</p>
|
|
|
|
<p>Vous hésitez entre <code>emacs</code> et <code>vim</code> ? Tout
|
|
le monde est passé par là. Jetez un coup d'œil à chacun des deux,
|
|
puis concentrez-vous sur celui qui vous paraît le plus sympathique et le
|
|
plus pratique ; et si vous hésitez encore, tirez-en un au
|
|
sort, ils se valent vraiment.</p>
|
|
|
|
|
|
<h3>Rendre un script exécutable</h3>
|
|
|
|
<p> Pour que le shell sache comment l'interpréter, un script shell doit
|
|
commencer par la ligne: </p>
|
|
|
|
<pre>#!/bin/sh</pre>
|
|
|
|
<p>
|
|
Il doit aussi avoir être exécutable (bit <code>x</code>). Le
|
|
<code>#!/bin/sh</code> sur la première ligne indique que ce script doit être
|
|
exécuté par le shell <code>sh</code> dont on indique le chemin
|
|
d'accès. Pour rendre un fichier exécutable, tapez :
|
|
</p>
|
|
|
|
<pre><span class="prompt">chaland ~</span> chmod u+x fichier
|
|
</pre>
|
|
|
|
<p class="continue">
|
|
(pour en savoir plus sur les droits attachés à un fichier, consultez la
|
|
page sur <a href="&url.tuteurs;unix/droits.html">les droits
|
|
d'accè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="presentation.html">présentation du shell</a>.
|
|
</p>
|
|
|
|
<p>
|
|
Quand vous exécutez un script, vous pouvez vous trouver à
|
|
n'importe quel endroit de l'arborescence de vos répertoires. Si le
|
|
répertoire courant ne se situe pas dans votre <code>PATH</code> et
|
|
que vous voulez exécuter un programme qui s'y trouve, vous ne pouvez
|
|
pas taper :
|
|
</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 :
|
|
</p>
|
|
|
|
<pre>
|
|
<span class="prompt">clipper ~</span> commande
|
|
zsh: command not found: commande</pre>
|
|
|
|
|
|
<h4>Spécifier le chemin d'une commande</h4>
|
|
|
|
<p>
|
|
Pour que le shell comprenne où chercher votre commande, il faut donc
|
|
spécifier l'emplacement de la commande en donnant son chemin, qu'il
|
|
soit absolu :
|
|
</p>
|
|
|
|
<pre>
|
|
<span class="prompt">clipper ~</span> /home/toto/repertoire/courant/commande
|
|
</pre>
|
|
|
|
<p class="continue">ou relatif : </p>
|
|
|
|
<pre>
|
|
<span class="prompt">clipper ~</span> repertoire/courant/commande
|
|
</pre>
|
|
|
|
<p class="continue">ou encore sous la forme : </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 :
|
|
</p>
|
|
|
|
<ul>
|
|
<li> devoir se rappeler dans quel répertoire se trouve chacune
|
|
d'entre elles ;</li>
|
|
<li> devoir taper à chaque fois le chemin de la commande.</li>
|
|
</ul>
|
|
|
|
<p>Il suffit donc de mettre tous vos scripts dans un même
|
|
ré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épertoire sera donc <code>/home/toto/bin</code>. </p>
|
|
|
|
<p>
|
|
Commencez donc par créer ce répertoire :
|
|
</p>
|
|
|
|
<pre>
|
|
<span class="prompt">clipper ~</span> mkdir bin
|
|
</pre>
|
|
|
|
<p>
|
|
Ensuite, vérifiez qu'il soit bien dans votre <code>PATH</code> :
|
|
</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écutables situé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 :
|
|
</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éraux des scripts shell</h2>
|
|
|
|
<h3>Une succession de commandes</h3>
|
|
|
|
<p> Si vous manipulez déjà 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 à l'ENS :
|
|
</p>
|
|
|
|
<pre>
|
|
<span class="prompt">clipper ~</span> mozilla &
|
|
<span class="prompt">clipper ~</span> mutt
|
|
</pre>
|
|
|
|
<p class="continue">vous pouvez vous créer le script suivant dans le
|
|
fichier <code>~/bin/amorce</code> :</p>
|
|
|
|
<pre>
|
|
#!/bin/sh
|
|
|
|
mozilla &
|
|
mutt
|
|
</pre>
|
|
|
|
<p>Ainsi, dès que vous vous connectez, vous pouvez taper
|
|
<code>amorce</code> dans le shell, et vos commandes s'exécuteront
|
|
automatiquement. </p>
|
|
|
|
|
|
<h3>Commentaires</h3>
|
|
<p>
|
|
Presque tous les langages informatiques autorisent d'insérer des
|
|
commentaires ; le shell n'échappe pas à la règle. Pour
|
|
cela, il suffit de faire précéder chaque ligne de commentaire du
|
|
caractère « # ». Exemple :
|
|
</p>
|
|
|
|
<pre>
|
|
#!/bin/sh
|
|
|
|
# Tout ce que j'écris ici ne sera pas lu.
|
|
echo "Ce que je tape ici sera lu."
|
|
</pre>
|
|
|
|
<p>
|
|
Les lignes blanches ne sont pas interprétées non
|
|
plus. N'hésitez donc surtout pas à 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ératif de lisibilité</h3>
|
|
|
|
<p>
|
|
Pourquoi espacer son script ? Pourquoi insérer des
|
|
commentaires ? Pour une seule et même raison :
|
|
<strong>votre script doit être lisible</strong>. Pourquoi être
|
|
lisible ? </p>
|
|
|
|
<p> D'abord, pour autrui : si d'autres gens lisent votre script, il
|
|
doit être intelligible, et les passages complexes doivent être
|
|
explicités par des commentaires.</p>
|
|
|
|
<p> Ensuite, pour vous-même ; au moment où vous écrivez un
|
|
script, vous comprenez tout, naturellement ; mais si vous le
|
|
relisez dans quelques mois, voire quelques années, les passages
|
|
obscurs risqueront d'être incompréhensibles, ce qui est
|
|
particulièrement pénible quand on essaye de <em>débuguer</em>
|
|
un programme, c'est-à-dire d'en corriger les erreurs.
|
|
</p>
|
|
|
|
|
|
<h2>Un script qui parle : la commande <code>echo</code></h2>
|
|
<p>
|
|
Maintenant que vous savez comment on peut exécuter un script, il s'agit
|
|
de le remplir... Commençons par ce qu'il y a de plus simple :
|
|
afficher du texte.
|
|
</p>
|
|
|
|
<h3>Hello World !</h3>
|
|
|
|
<p>
|
|
Traditionnellement, on commence par faire un programme qui affiche
|
|
simplement la ligne « Hello world » (ce qui signifie en
|
|
anglais : bonjour au monde entier). Faites donc un fichier
|
|
<code>helloworld</code> contenant les lignes suivantes :
|
|
</p>
|
|
|
|
<pre>
|
|
#!/bin/sh
|
|
|
|
# Fichier "helloworld"
|
|
echo "Hello world"
|
|
</pre>
|
|
|
|
<p>
|
|
Exécutez ensuite ce programme, par exemple en tapant, dans le répertoire
|
|
où il se trouve :
|
|
</p>
|
|
|
|
<pre><span class="prompt">clipper ~ $</span> ./helloworld
|
|
Hello world</pre>
|
|
|
|
<p>
|
|
Ça y est, vous avez créé votre premier programme ! Lancez-le autant
|
|
de vous que vous voulez, vous avez bien mérité d'être fier de vous.
|
|
</p>
|
|
|
|
<p>
|
|
Exercice : francisez ce script.
|
|
</p>
|
|
|
|
|
|
<h3>La commande <code>echo</code></h3>
|
|
|
|
<p>
|
|
La commande <code>echo</code> sert à 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ées et sorties</a>). Chaque
|
|
ligne de texte est écrite sur une ligne à part. Exemple :
|
|
</p>
|
|
|
|
<pre>
|
|
#!/bin/sh
|
|
# Fichier "bonjour"
|
|
|
|
echo "Bonjour... "
|
|
echo "Comment allez-vous ?"
|
|
</pre>
|
|
|
|
<p class="continue">affiche les lignes suivantes :</p>
|
|
|
|
<pre>
|
|
Bonjour...
|
|
Comment allez-vous ?
|
|
</pre>
|
|
|
|
<p class="continue">et non :</p>
|
|
|
|
<pre>
|
|
Bonjour... Comment allez-vous ?
|
|
</pre>
|
|
|
|
|
|
<h4>Annuler le retour chariot</h4>
|
|
|
|
<p>
|
|
Si vous voulez annuler le retour chariot qui a lieu par défaut à la fin
|
|
de toute commande <code>echo</code>, il faut utiliser l'option
|
|
<code>-n</code>. Le programme sera alors :
|
|
</p>
|
|
|
|
<pre>
|
|
#!/bin/sh
|
|
|
|
echo -n "Bonjour..."
|
|
echo "Comment allez-vous ?"
|
|
</pre>
|
|
|
|
<p class="continue">
|
|
Alors seulement, vous pourrez avoir :
|
|
</p>
|
|
|
|
<pre>
|
|
Bonjour... Comment allez-vous ?
|
|
</pre>
|
|
|
|
|
|
<h4>Citer des variables</h4>
|
|
|
|
<p>Faisons mieux encore : 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>
|
|
|
|
<p>La variable <code>USER</code> contient le login de
|
|
l'utilisateur ; la variable <code>PWD</code> (pour <em>print
|
|
working directory</em>) affiche le répertoire courant. Faisons donc le
|
|
script suivant :</p>
|
|
|
|
<pre>
|
|
#/bin/sh
|
|
# Fichier "mon-pwd"
|
|
|
|
echo "Bonjour $USER..."
|
|
echo "Tu es actuellement dans le répertoire $PWD."
|
|
</pre>
|
|
|
|
<p>Comme vous pouvez le remarquer, pour citer le contenu d'une variable,
|
|
on ajoute le signe dollar ($) devant son nom.</p>
|
|
|
|
|
|
|
|
|
|
<h2>Un script qui écoute : la commande <code>read</code></h2>
|
|
|
|
<p>Parler c'est bien, é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ès intime...</p>
|
|
|
|
<p>
|
|
Nous allons donc lui donner la faculté d'écouter, grâce à la commande
|
|
<code>read</code>. Prenons le script suivant :
|
|
</p>
|
|
|
|
<pre>
|
|
#!/bin/sh
|
|
# Fichier "mon-nom"
|
|
|
|
echo "Bonjour... Comment vous-appelez-vous ?"
|
|
read nom
|
|
echo "Je vous souhaite, $nom, de passer une bonne journée."
|
|
</pre>
|
|
|
|
<p>Vous connaissez déjà la commande <code>echo</code>. La commande
|
|
<code>read</code> permet de lire des variables. Si vous exécutez ce
|
|
script, après avoir affiché la ligne </p>
|
|
|
|
<pre>
|
|
Bonjour... Comment vous-appelez-vous ?
|
|
</pre>
|
|
|
|
<p class="continue">le shell va attendre que vous tapiez votre
|
|
nom. Tapez par exemple <code>Toto</code>, puis appuyez sur Entrée, et
|
|
vous verrez :</p>
|
|
|
|
<pre>
|
|
Bonjour... Comment vous-appelez-vous ?
|
|
<em>Toto</em>
|
|
Je vous souhaite, Toto, de passer une bonne journée.</pre>
|
|
|
|
<div class="attention">
|
|
La commande <code>read</code> doit être suivie du seul nom de la
|
|
variable, <strong>non précédé du signe dollar</strong>. <em>Le signe
|
|
dollar ne doit précéder le nom de la variable que lorsque l'on cite son
|
|
contenu.</em>
|
|
</div>
|
|
|
|
<h3>Lire plusieurs variables</h3>
|
|
|
|
<p>
|
|
La commande <code>read</code> permet également de lire plusieurs
|
|
variables. Il suffit pour cela d'indiquer à la suite les noms des
|
|
différentes variables. Exemple :
|
|
</p>
|
|
|
|
<pre>
|
|
#!/bin/sh
|
|
# Fichier "administration"
|
|
|
|
echo "Écrivez votre nom puis votre prénom :"
|
|
read nom prenom
|
|
echo "Nom : $nom"
|
|
echo "Prénom : $prenom"
|
|
</pre>
|
|
|
|
<p>Vous aurez :</p>
|
|
|
|
<pre>
|
|
Écrivez votre nom puis votre prénom :
|
|
<em>Hugo Victor</em>
|
|
Nom : Hugo
|
|
Prénom : Victor
|
|
</pre>
|
|
|
|
|
|
|
|
<h3>Appuyer sur Entrée pour continuer</h3>
|
|
|
|
<p>Nous avons vu comment utiliser <code>read</code> avec un seul
|
|
argument et avec plusieurs arguments ; il reste à voir l'usage de
|
|
<code>read</code> <em>sans</em> argument. Oui, c'est possible !
|
|
Cela équivaut simplement à attendre un réaction de l'utilisateur, mais
|
|
sans mémoriser ce qu'il tape.</p>
|
|
|
|
<p> Concrètement, cela est très utile après un message « Appuyez
|
|
sur Entrée pour continuer. » Exemple :</p>
|
|
|
|
<pre>
|
|
#!/bin/sh
|
|
# Fichier "continuer"
|
|
|
|
echo "Quelle est la différence entre un canard ?"
|
|
echo "(Appuyez sur Entrée pour avoir la réponse)"
|
|
read
|
|
echo "Les pattes, surtout la gauche."
|
|
</pre>
|
|
|
|
|
|
<div class="metainformation">
|
|
Auteur : Baptiste Mélès.
|
|
Dernière modification le <date value="$Date: 2005-07-05 07:18:06 $" />.
|
|
</div>
|
|
|
|
</body>
|
|
</html>
|