Bap: Ajout au CVS : une erreur de conscrit...
This commit is contained in:
parent
aaf4f2e59a
commit
7c56ab2bd4
5 changed files with 1789 additions and 0 deletions
500
unix/shell/commande.tml
Normal file
500
unix/shell/commande.tml
Normal file
|
@ -0,0 +1,500 @@
|
||||||
|
<?xml version="1.0" encoding="ISO-8859-1"?>
|
||||||
|
<!DOCTYPE html
|
||||||
|
PUBLIC "-//ENS/Tuteurs//DTD TML 1//EN"
|
||||||
|
"tuteurs://DTD/tml.dtd">
|
||||||
|
<html>
|
||||||
|
<head>
|
||||||
|
<title>Commandes</title>
|
||||||
|
</head>
|
||||||
|
<body>
|
||||||
|
|
||||||
|
<h1>Le shell en ligne de commande</h1>
|
||||||
|
|
||||||
|
<h2>Créer des processus</h2>
|
||||||
|
|
||||||
|
<p> Le shell a la faculté de lancer de nombreux programmes, sinon
|
||||||
|
tous. C'est une des raisons pour lesquelles on peut dire que c'est un
|
||||||
|
outil extrêmement puissant.
|
||||||
|
</p>
|
||||||
|
|
||||||
|
<h3>Qu'est-ce qu'un processus ?</h3>
|
||||||
|
|
||||||
|
<p> Lancer un programme, c'est créer un
|
||||||
|
<em>processus</em>. Tautologisons : <strong>un processus est une
|
||||||
|
instance d'exécution d'un programme</strong>, c'est-à-dire
|
||||||
|
l'exécution particulière d'un programme universel (<i>i.e</i> qui
|
||||||
|
n'est pas réductible à l'une de ses exécutions). </p>
|
||||||
|
|
||||||
|
<p>Par exemple, si je lance Mozilla, un processus se crée, du nom de
|
||||||
|
<code>mozilla</code>. Ensuite, sans fermer ce programme, je lance une
|
||||||
|
deuxième fois Mozilla ; un nouveau processus se crée, du nom
|
||||||
|
de <code>mozilla</code> également. J'ai donc deux processus
|
||||||
|
distincts, même s'ils concernent le même programme. Et à chaque
|
||||||
|
fois que je lance un programme, un processus se crée.
|
||||||
|
</p>
|
||||||
|
|
||||||
|
<h3>Généalogie des processus</h3>
|
||||||
|
|
||||||
|
<p> Dans notre exemple, nous avons deux processus
|
||||||
|
<code>mozilla</code>. Ils sont indépendants l'un de l'autre :
|
||||||
|
quoi qu'il puisse se passer dans l'un, cela ne devrait pas influer sur
|
||||||
|
le comportement de l'autre.
|
||||||
|
</p>
|
||||||
|
|
||||||
|
<p> Toutefois, s'ils sont indépendants l'un de l'autre, tous deux
|
||||||
|
dépendent du processus qui les a lancés. Eh oui, <strong>le shell
|
||||||
|
est un programme comme un autre, donc chacune de ses exécutions
|
||||||
|
correspond également à la création d'un processus</strong>. Si
|
||||||
|
vous lancez trois shells en même temps, par exemple dans trois
|
||||||
|
terminaux différents, vous aurez trois processus <code>shell</code>
|
||||||
|
distincts. </p>
|
||||||
|
|
||||||
|
<p>
|
||||||
|
Les processus entretiennent entre eux des relations de parenté. Mais
|
||||||
|
comme les processus ont tous le même sexe, <strong>chaque processus
|
||||||
|
n'a qu'un parent. Un processus peut avoir plusieurs enfants</strong>.
|
||||||
|
</p>
|
||||||
|
|
||||||
|
<p> Le shell est, comme nous venons de le voir, <strong>un processus qui
|
||||||
|
peut enfanter d'autres processus</strong>. Par exemple, à chaque fois
|
||||||
|
que je tape <code>mozilla</code>, mon shell crée un processus
|
||||||
|
<code>mozilla</code>. </p>
|
||||||
|
|
||||||
|
|
||||||
|
<h3>Lancer des processus en arrière-plan</h3>
|
||||||
|
<p>
|
||||||
|
<strong>Par défaut, le shell met le processus enfant en
|
||||||
|
avant-plan</strong>. Cela veut dire que si je tape simplement :
|
||||||
|
</p>
|
||||||
|
|
||||||
|
<pre>
|
||||||
|
<span class="prompt">chaland ~</span> mozilla
|
||||||
|
</pre>
|
||||||
|
|
||||||
|
<p class="continue">
|
||||||
|
le processus <code>mozilla</code> prend la main, et le shell ne
|
||||||
|
réagit plus (il n'affiche même plus l'invite de commande) avant
|
||||||
|
la fin du processus enfant. Ce n'est que lorsque le processus
|
||||||
|
<code>mozilla</code> prend fin (si je ferme ce programme, par exemple)
|
||||||
|
que le shell reprend la main.
|
||||||
|
</p>
|
||||||
|
|
||||||
|
<p>Ce comportement par défaut n'est parfois pas très pratique. Par
|
||||||
|
exemple, si je veux lancer Mozilla, mais aussi Emacs et d'autres
|
||||||
|
programmes qui s'ouvrent dans leur propre fenêtre, je suis obligé
|
||||||
|
d'ouvrir à chaque fois un nouveau terminal avec un nouveau shell, et
|
||||||
|
ce uniquement pour y taper une commande, après quoi le shell se
|
||||||
|
retrouve inutilisable jusqu'à la fin de chacun de ces
|
||||||
|
programmes. </p>
|
||||||
|
|
||||||
|
<p>Il faudrait donc que l'on puisse <strong>lancer des processus enfants en
|
||||||
|
arrière-plan</strong>, de telle sorte que ces processus se lancent
|
||||||
|
dans leur propre fenêtre et me permettent toutefois de dialoguer avec
|
||||||
|
le shell sans avoir à :</p>
|
||||||
|
<ul>
|
||||||
|
<li> ouvrir un nouveau shell dans une nouvelle fenêtre ;</li>
|
||||||
|
<li> attendre la fin de l'un de ces processus.</li>
|
||||||
|
</ul>
|
||||||
|
|
||||||
|
<p>Pour cela, il faut ajouter le signe « & » à la
|
||||||
|
fin d'une ligne de commande. On peut ainsi taper :</p>
|
||||||
|
|
||||||
|
<pre>
|
||||||
|
<span class="prompt">chaland ~</span> mozilla &
|
||||||
|
<span class="prompt">chaland ~</span> mozilla &
|
||||||
|
<span class="prompt">chaland ~</span>
|
||||||
|
</pre>
|
||||||
|
|
||||||
|
<p class="continue">et de la sorte, un même shell peut engendrer
|
||||||
|
autant de processus que vous voulez.</p>
|
||||||
|
|
||||||
|
|
||||||
|
<h3>Émanciper un processus enfant</h3>
|
||||||
|
<p>La vie est déjà plus pratique comme cela. Mais parfois, on
|
||||||
|
aimerait que le processus enfant survive au processus parent. Car par
|
||||||
|
défaut, <strong>la mort d'un processus parent entraîne celle de
|
||||||
|
tous ses enfants</strong>. Par exemple, si le shell qui a enfanté les
|
||||||
|
deux processus <code>mozilla</code> vient à décéder (si je le
|
||||||
|
ferme brutalement, ou s'il plante), les deux processus
|
||||||
|
<code>mozilla</code> le suivront dans la mort. </p>
|
||||||
|
|
||||||
|
<p>
|
||||||
|
Il faudrait donc qu'un processus parent puisse émanciper des
|
||||||
|
processus enfants, pour que sa propre mort n'entraîne pas les
|
||||||
|
leurs. Pour cela, il faut utiliser les symboles
|
||||||
|
« &! ». Par exemple, si je tape :
|
||||||
|
</p>
|
||||||
|
|
||||||
|
<pre>
|
||||||
|
<span class="prompt">chaland ~</span> mozilla &!
|
||||||
|
<span class="prompt">chaland ~</span> mozilla &!
|
||||||
|
<span class="prompt">chaland ~</span>
|
||||||
|
</pre>
|
||||||
|
|
||||||
|
<p class="continue">puis que je ferme brutalement le shell en tapant
|
||||||
|
Ctrl-D et en ignorant d'éventuels avertissements, le shell
|
||||||
|
disparaîtra, mais pas les processus <code>mozilla</code>. </p>
|
||||||
|
|
||||||
|
|
||||||
|
<h2>Arguments et options</h2>
|
||||||
|
<p> Jusqu'ici, l'exemple de processus enfant que nous avons pris
|
||||||
|
était relativement simple : il s'agissait de la commande
|
||||||
|
<code>mozilla</code>, que l'on peut lancer en tapant simplement son
|
||||||
|
nom. </p>
|
||||||
|
|
||||||
|
<p>
|
||||||
|
Jusqu'ici, on peut se dire que la ligne de commande, c'est comme quand
|
||||||
|
on clique sur une icône, sauf que c'est plus fatigant. Effectivement,
|
||||||
|
pourquoi se fatiguer à taper une suite de caractères quand il
|
||||||
|
suffit d'appuyer une ou deux fois sur le bouton d'une souris ?
|
||||||
|
</p>
|
||||||
|
|
||||||
|
<p>
|
||||||
|
C'est dans l'usage des arguments et des options que la ligne de commande
|
||||||
|
commence à révéler une partie de sa puissance, et de sa nette
|
||||||
|
supériorité sur les interfaces graphiques.
|
||||||
|
</p>
|
||||||
|
|
||||||
|
|
||||||
|
<h3>Les arguments</h3>
|
||||||
|
<p>Un argument est une suite de caractères que l'on donne à une
|
||||||
|
commande et qui lui indique comment se comporter. Les options sont un
|
||||||
|
type d'argument. </p>
|
||||||
|
|
||||||
|
|
||||||
|
<h4>Exemples</h4>
|
||||||
|
|
||||||
|
<p>Par exemple, si je veux ouvrir le fichier <code>hermocrate.txt</code>
|
||||||
|
avec l'éditeur de texte <code>nano</code>, j'ai le choix entre deux
|
||||||
|
possibilités :</p>
|
||||||
|
|
||||||
|
<ul>
|
||||||
|
<li> ou bien je tape :
|
||||||
|
<pre><span class="prompt">chaland ~</span> nano </pre>
|
||||||
|
puis Ctrl-R pour indiquer d'ouvrir un fichier, puis Ctrl-T
|
||||||
|
pour voir la liste des fichiers, puis les flèches pour choisir mes
|
||||||
|
fichiers, enfin Entrée pour sélectionner
|
||||||
|
<code>hermocrate.txt</code> — mais tout cela est bien
|
||||||
|
fastidieux ; </li>
|
||||||
|
|
||||||
|
<li> ou bien je tape directement :
|
||||||
|
<pre><span class="prompt">chaland ~</span> nano hermocrate.txt</pre>
|
||||||
|
</li>
|
||||||
|
</ul>
|
||||||
|
|
||||||
|
<p>Ou encore, pour reprendre l'exemple de Mozilla, si je veux aller voir
|
||||||
|
la page des tuteurs et que ce n'est pas ma page d'accueil par défaut
|
||||||
|
(ce qui est un tort !), je peux taper :</p>
|
||||||
|
|
||||||
|
<pre><span class="prompt">chaland ~</span> mozilla http://www.tuteurs.ens.fr/</pre>
|
||||||
|
|
||||||
|
<h3>Les options</h3>
|
||||||
|
<p>
|
||||||
|
Les options sont un cas particulier d'arguments, qui donnent au
|
||||||
|
programme que l'on exécute toutes sortes d'information, souvent
|
||||||
|
plus ou moins périphériques, en général moins importantes
|
||||||
|
que les arguments.
|
||||||
|
</p>
|
||||||
|
|
||||||
|
<p>Sous Unix, les options commencent généralement par un
|
||||||
|
tiret. Certaines options peuvent à leur tour prendre des
|
||||||
|
arguments.</p>
|
||||||
|
|
||||||
|
<p>Par exemple, si l'on veut ouvrir un fichier au format MS-DOS, on peut
|
||||||
|
taper :</p>
|
||||||
|
|
||||||
|
<pre><span class="prompt">chaland ~</span> nano -D hermocrate.txt</pre>
|
||||||
|
|
||||||
|
|
||||||
|
<h4>Options à arguments</h4>
|
||||||
|
|
||||||
|
<p>
|
||||||
|
L'option <code>-r</code> de <code>nano</code> prend un argument ;
|
||||||
|
ainsi, si l'on veut que Nano coupe les lignes au bout de 75
|
||||||
|
caractères, on doit ouvrir Nano en tapant :
|
||||||
|
</p>
|
||||||
|
|
||||||
|
<pre><span class="prompt">chaland ~</span> nano -r 75 hermocrate.txt</pre>
|
||||||
|
|
||||||
|
|
||||||
|
<h4>Options à nom long</h4>
|
||||||
|
|
||||||
|
<p>Traditionnellement, et pur des raisons de concision, la majorité
|
||||||
|
des options, sous Unix, est composée d'un tiret et d'une seule
|
||||||
|
lettre. Toutefois, pour des raisons pratiques, il peut également
|
||||||
|
exister des noms d'option longs ; ils sont en général
|
||||||
|
précédés, non d'un, mais de deux tirets. Exemple :</p>
|
||||||
|
|
||||||
|
<pre><span class="prompt">chaland ~</span> nano --fill=75 hermocrate.txt</pre>
|
||||||
|
|
||||||
|
<p class="continue">Dans cet exemple, il se trouve que l'option à nom
|
||||||
|
long <code>--fill=</code> équivaut à l'option à nom
|
||||||
|
court <code>-r</code>. Mais toutes les commandes courtes n'ont pas
|
||||||
|
systématiquement leur équivalent à nom long, et vice versa.</p>
|
||||||
|
|
||||||
|
<h2>Jokers et citations</h2>
|
||||||
|
|
||||||
|
<h3><a name="raccourcis">Raccourcis pour les noms de fichiers : les
|
||||||
|
jokers</a></h3>
|
||||||
|
|
||||||
|
<p>
|
||||||
|
Il est souvent ennuyeux d'avoir à taper une longue liste de fichiers
|
||||||
|
pour les donner en arguments à une commande, comme :
|
||||||
|
</p>
|
||||||
|
|
||||||
|
<pre>cc -o foo bar.c gee.c buz.c gog.c</pre>
|
||||||
|
|
||||||
|
<p>
|
||||||
|
Pour éviter ces problèmes, on peut utiliser des <em>jokers</em>
|
||||||
|
(<em>wildcards</em> en anglais). Pourquoi ce nom ? Eh bien, dans
|
||||||
|
certains jeux de cartes, le joker permet de remplacer n'importe quelle
|
||||||
|
carte ; dans le shell, les jokers permettent de remplacer n'importe
|
||||||
|
quel caractère ou n'importe quelle séquence de caractères.
|
||||||
|
</p>
|
||||||
|
|
||||||
|
<p>
|
||||||
|
Il existe principalement trois types de jokers :
|
||||||
|
</p>
|
||||||
|
|
||||||
|
<ul>
|
||||||
|
<li> l'étoile (*), qui remplace n'importe quelle séquence de
|
||||||
|
caractères ;</li>
|
||||||
|
<li> le point d'interrogation, qui remplace n'importe quel
|
||||||
|
caractère ;</li>
|
||||||
|
<li> les crochets ([]), qui remplacent n'importe quel caractère d'une
|
||||||
|
liste déterminée.</li>
|
||||||
|
</ul>
|
||||||
|
|
||||||
|
<h4>L'étoile : *</h4>
|
||||||
|
|
||||||
|
<p>
|
||||||
|
Une <strong>étoile</strong> <code>*</code> dans un nom de fichier est
|
||||||
|
interprétée par le shell comme « n'importe quelle séquence de
|
||||||
|
caractères » (mais ça ignore les fichiers dont le nom commence par un
|
||||||
|
point). Exemple :
|
||||||
|
</p>
|
||||||
|
|
||||||
|
<pre>cc -o foo *.c</pre>
|
||||||
|
|
||||||
|
<p>
|
||||||
|
Pour interpréter l'étoile, le shell va faire la liste de tous les noms de
|
||||||
|
fichiers du répertoire courant qui ne commencent pas par <code>.</code> et
|
||||||
|
qui finissent par <code>.c</code>. Ensuite, il remplace <code>*.c</code>
|
||||||
|
par cette liste (triée par ordre alphabétique) dans la ligne de commande, et
|
||||||
|
exécute le résultat, c'est-à-dire par exemple :
|
||||||
|
</p>
|
||||||
|
|
||||||
|
<pre>cc -o foo bar.c buz.c foo.c gee.c gog.c</pre>
|
||||||
|
|
||||||
|
<h4>Le point d'interrogation : ?</h4>
|
||||||
|
|
||||||
|
<p>
|
||||||
|
On a aussi le <strong>point d'interrogation</strong> <code>?</code>, qui
|
||||||
|
remplace un (et exactement un) caractère quelconque (sauf un point en début
|
||||||
|
de nom). Par exemple, <code>ls *.?</code> liste tous les dont l'extension
|
||||||
|
ne comporte qu'un caractère (<code>.c</code>, <code>.h</code>...).
|
||||||
|
</p>
|
||||||
|
|
||||||
|
<h4>Les crochets : []</h4>
|
||||||
|
|
||||||
|
<p>
|
||||||
|
La forme <code>[abcd]</code> remplace un caractère quelconque parmi
|
||||||
|
<code>a</code>, <code>b</code>, <code>c</code>, <code>d</code>. Enfin,
|
||||||
|
<code>[^abcd]</code> remplace un
|
||||||
|
caractère quelconque qui ne se trouve pas parmi <code>a</code>, <code>b</code>,
|
||||||
|
<code>c</code>, <code>d</code>.
|
||||||
|
</p>
|
||||||
|
|
||||||
|
<h4>Exemple</h4>
|
||||||
|
|
||||||
|
<pre>echo /users/*</pre>
|
||||||
|
|
||||||
|
<p class="continue">
|
||||||
|
affiche à peu près la même chose que
|
||||||
|
</p>
|
||||||
|
|
||||||
|
<pre>ls /users</pre>
|
||||||
|
|
||||||
|
<p class="continue">
|
||||||
|
(La commande <code>echo</code> se contente d'afficher ses arguments.)
|
||||||
|
</p>
|
||||||
|
|
||||||
|
<div class="attention">
|
||||||
|
<p>
|
||||||
|
&icone.attention; Attention :
|
||||||
|
</p>
|
||||||
|
|
||||||
|
<ul>
|
||||||
|
|
||||||
|
<li><strong>C'est le shell qui fait le remplacement des arguments
|
||||||
|
contenant un joker</strong>. On ne peut donc pas faire <code>mv *.c
|
||||||
|
*.bak</code>, car le shell va passer à <code>mv</code> les arguments
|
||||||
|
<code>foo.c bar.c foo.bak bar.bak</code>, et <code>mv</code> ne sait pas
|
||||||
|
quel fichier remplacer. </li>
|
||||||
|
|
||||||
|
<li> <strong>Attention aux espaces</strong>. Si vous tapez <code>rm *
|
||||||
|
~</code>, le shell remplace l'étoile par la liste des fichiers présents,
|
||||||
|
et ils seront tous effacés. Si vous tapez <code>rm *~</code>, seuls les
|
||||||
|
fichiers dont le nom finit par un tilde seront effacés. </li>
|
||||||
|
|
||||||
|
</ul>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="encadre">
|
||||||
|
<p>
|
||||||
|
<strong>Interlude :</strong> comment effacer un fichier nommé
|
||||||
|
<code>?*</code> ? On ne peut pas taper <code>rm ?*</code> car le shell
|
||||||
|
remplace <code>?*</code> par la liste de tous les fichiers du répertoire
|
||||||
|
courant. On peut taper <code>rm -i *</code> qui supprime tous les
|
||||||
|
fichiers, mais en demandant confirmation à chaque fichier. On répond
|
||||||
|
<code>n</code> à toutes les questions sauf <code>rm: remove ?*</code>.
|
||||||
|
Autre méthode: utiliser les mécanismes de citation.
|
||||||
|
</p>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<h3><a name="quotation">Contourner les jokers : la citation (<i
|
||||||
|
lang="en">quotation</i>)</a></h3>
|
||||||
|
|
||||||
|
<p>
|
||||||
|
Avec tous ces caractères spéciaux, comment faire pour passer des
|
||||||
|
arguments bizarres à une commande ? Par exemple, comment faire
|
||||||
|
afficher un point d'interrogation suivi d'une étoile et d'un dollar par
|
||||||
|
<code>echo</code> ?</p>
|
||||||
|
|
||||||
|
<p>
|
||||||
|
On ne peut pas les taper directement dans la ligne de commande (ici,
|
||||||
|
avec le shell <code>zsh</code>), car le shell essaye de les interpréter
|
||||||
|
comme des jokers :
|
||||||
|
</p>
|
||||||
|
|
||||||
|
<pre><span class="prompt">chaland ~</span> echo ?*$
|
||||||
|
zsh: no matches found: ?*$</pre>
|
||||||
|
|
||||||
|
<p> Il faut donc indiquer au shell de ne pas interpréter ces caractères
|
||||||
|
comme des jokers. Pour cela, nous allons utiliser des mécanismes fournis
|
||||||
|
par le shell : les <i lang="en">quotations</i> (mot anglais
|
||||||
|
signifiant <em>citation</em>).
|
||||||
|
</p>
|
||||||
|
|
||||||
|
<p>
|
||||||
|
Les mécanismes de citation sont les suivants :
|
||||||
|
</p>
|
||||||
|
|
||||||
|
<ul>
|
||||||
|
<li> le backslash (<code>\</code>), qui protège un caractère de
|
||||||
|
l'interprétation par le shell ;</li>
|
||||||
|
<li> les apostrophes ou <i lang="en">simple quotes</i>
|
||||||
|
(<code>'</code>), qui protègent une chaîne de caractères de
|
||||||
|
l'interprétation par le shell ;</li>
|
||||||
|
<li> les guillemets doubles ou <i lang="en">double quotes</i>
|
||||||
|
(<code>"</code>), qui protègent également une chaîne de caractères
|
||||||
|
de l'interprétation par le shell, mais avec plus de souplesse que les
|
||||||
|
précédents ;</li>
|
||||||
|
<li> les <i lang="en">backquotes</i> (<code>`</code>), qui cite la
|
||||||
|
sortie d'une commande.</li>
|
||||||
|
</ul>
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
<h4>Le backslash (<code>\</code>)</h4>
|
||||||
|
|
||||||
|
<p>
|
||||||
|
Il suffit de précéder un caractère spécial d'un backslash, et le shell
|
||||||
|
remplace ces deux caractères par le caractère spécial seul. Évidemment, le
|
||||||
|
backslash est lui-même un caractère spécial.
|
||||||
|
</p>
|
||||||
|
|
||||||
|
<p>
|
||||||
|
Exemples :
|
||||||
|
</p>
|
||||||
|
|
||||||
|
<pre>
|
||||||
|
<span class="prompt">chaland ~ $</span> echo \?\*\$
|
||||||
|
?*$
|
||||||
|
<span class="prompt">chaland ~ $</span> echo \\\?\\\*\\\$
|
||||||
|
\?\*\$</pre>
|
||||||
|
|
||||||
|
<h4>Les apostrophes ou simples quotes (<code>'</code>)</h4>
|
||||||
|
|
||||||
|
<p>
|
||||||
|
Un autre moyen est d'inclure une chaîne de caractères entre apostrophes
|
||||||
|
(simples quotes) <code>'</code>. Tout ce qui se trouve entre deux
|
||||||
|
apostrophes sera passé tel quel par le shell à la
|
||||||
|
commande. Exemple :
|
||||||
|
</p>
|
||||||
|
|
||||||
|
<pre>
|
||||||
|
<span class="prompt">chaland ~ $</span> echo '$?*'
|
||||||
|
$?*</pre>
|
||||||
|
|
||||||
|
<h4>Les guillemets doubles ou doubles quotes (<code>"</code>)</h4>
|
||||||
|
|
||||||
|
<p>
|
||||||
|
Les guillemets se comportent comme les apostrophes, à une exception près: les
|
||||||
|
dollars et les backslashes sont interprétés entre les guillemets.
|
||||||
|
Exemple :
|
||||||
|
</p>
|
||||||
|
|
||||||
|
<pre>
|
||||||
|
<span class="prompt">chaland ~ $</span> echo "$HOME/*"
|
||||||
|
/users/87/maths/doligez/*</pre>
|
||||||
|
|
||||||
|
<p>
|
||||||
|
Une technique utile: Quand on juxtapose deux chaînes de caractères
|
||||||
|
quotées, le shell les concatène, et elles ne forment qu'un argument.
|
||||||
|
Exemple :
|
||||||
|
</p>
|
||||||
|
|
||||||
|
<pre>
|
||||||
|
<span class="prompt">chaland ~ $</span> echo "'"'"'
|
||||||
|
'"</pre>
|
||||||
|
|
||||||
|
<p>
|
||||||
|
Quant aux interactions plus compliquées (backslashes à l'intérieur des
|
||||||
|
guillemets, guillemets à l'intérieur des apostrophes, etc.), le meilleur moyen
|
||||||
|
de savoir si ça donne bien le résultat attendu est d'essayer. La commande
|
||||||
|
<code>echo</code> est bien utile dans ce cas.
|
||||||
|
</p>
|
||||||
|
|
||||||
|
<h4>Les backquotes (<code>`</code>)</h4>
|
||||||
|
|
||||||
|
<p>
|
||||||
|
Dernière forme de citation : <code>`<em>commande</em>`</code>. Le
|
||||||
|
shell exécute la <em>commande</em> indiquée entre backquotes, lit la
|
||||||
|
sortie de la commande mot par mot, et remplace <code>`</code>
|
||||||
|
<em>commande</em> <code>`</code> par la liste de ces mots.
|
||||||
|
Exemple :
|
||||||
|
</p>
|
||||||
|
|
||||||
|
<pre>
|
||||||
|
<span class="prompt">chaland ~ $</span> echo `ls`
|
||||||
|
Mail News bin foo lib misc mur notes.aux notes.dvi notes.log
|
||||||
|
notes.tex planar text
|
||||||
|
<span class="prompt">chaland ~ $</span> ls -l `which emacs`
|
||||||
|
-rwxr-xr-t 1 root taff 978944 Jul 16 1991 /usr/local/bin/emacs</pre>
|
||||||
|
|
||||||
|
<p>
|
||||||
|
La commande <code>which <em>cmd</em></code> employée ci-dessus affiche sur sa
|
||||||
|
sortie le nom absolu du fichier exécuté par le shell quand on lance la
|
||||||
|
commande it <em>cmd</em> :
|
||||||
|
</p>
|
||||||
|
|
||||||
|
<pre>
|
||||||
|
<span class="prompt">chaland ~ $</span> which emacs
|
||||||
|
/usr/local/bin/emacs</pre>
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
<p>Vous êtes maintenant en mesure de faire ces <a
|
||||||
|
href="&url.tuteurs;unix/exercices/">exercices</a> pour vous
|
||||||
|
entraîner.</p>
|
||||||
|
|
||||||
|
|
||||||
|
<div class="metainformation">
|
||||||
|
Basé sur un polycopié de Roberto Di Cosmo, Xavier Leroy et Damien Doligez.
|
||||||
|
Modifications : Nicolas George, Baptiste Mélès.
|
||||||
|
Dernière modification le <date value="$Date: 2005-05-31 11:33:37 $" />.
|
||||||
|
</div>
|
||||||
|
|
||||||
|
</body>
|
||||||
|
</html>
|
392
unix/shell/entreesortie.tml
Normal file
392
unix/shell/entreesortie.tml
Normal file
|
@ -0,0 +1,392 @@
|
||||||
|
<?xml version="1.0" encoding="ISO-8859-1"?>
|
||||||
|
<!DOCTYPE html
|
||||||
|
PUBLIC "-//ENS/Tuteurs//DTD TML 1//EN"
|
||||||
|
"tuteurs://DTD/tml.dtd">
|
||||||
|
<html>
|
||||||
|
<head>
|
||||||
|
<title>Entrée/sortie</title>
|
||||||
|
</head>
|
||||||
|
<body>
|
||||||
|
|
||||||
|
<h1>Entrée, sortie, redirection</h1>
|
||||||
|
|
||||||
|
<h2><a name="redirections">Entrée et sortie</a></h2>
|
||||||
|
|
||||||
|
<h3>Que sont l'entrée et la sortie d'une commande ?</h3>
|
||||||
|
|
||||||
|
<p>
|
||||||
|
Un programme consiste à traiter des données, et à renvoyer des données
|
||||||
|
transformées : il transforme des informations, et c'est pourquoi
|
||||||
|
l'on parle d'<em>informatique</em>.</p>
|
||||||
|
|
||||||
|
<p> Prenons le programme <code>hachoir</code>, par exemple : on y
|
||||||
|
fait entrer des choses, elles sortent sous une autre forme, et dans
|
||||||
|
l'intervalle, elles subissent des transformations régulières. Par
|
||||||
|
exemple, on fait entrer une vache, il en ressort du steak haché ;
|
||||||
|
on y fait entrer des carottes, il en ressort des carottes rapées.
|
||||||
|
</p>
|
||||||
|
|
||||||
|
<p>
|
||||||
|
Deux concepts permettent de modéliser cette transformation
|
||||||
|
d'informations : les concepts d'entrée et de
|
||||||
|
sortie. L'<strong>entrée</strong>, c'est la vache ou les carottes ;
|
||||||
|
la <strong>sortie</strong>, c'est le steak haché ou les carottes
|
||||||
|
rapées.
|
||||||
|
</p>
|
||||||
|
|
||||||
|
<h3>Sortie standard et sortie d'erreur</h3>
|
||||||
|
|
||||||
|
<p>
|
||||||
|
Mais cette première distinction entre entrée et sortie ne suffit pas,
|
||||||
|
car la sortie d'un programme, c'est-à-dire les messages qu'il renvoie,
|
||||||
|
sont de deux ordres : il y a les <em>messages normaux</em> relevant
|
||||||
|
de la transformation d'informations (par exemple le steak haché ou les
|
||||||
|
carottes rapées), mais il y a aussi des <em>messages d'erreur</em>.</p>
|
||||||
|
|
||||||
|
<p> Par exemple, si vous mettez, sur le tapis roulant qui mène au
|
||||||
|
hachoir, un objet trop gros pour y rentrer, le hachoir, s'il est bien
|
||||||
|
conçu, devra vous prévenir qu'il n'arrive pas à hacher un objet si
|
||||||
|
gros. Et ce message, quoiqu'il sorte aussi bien du hachoir que le steak
|
||||||
|
haché, ne doit pas être traité de la même façon à sa sortie, et n'est
|
||||||
|
pas suivi des mêmes conséquences. C'est pourquoi l'on distingue la
|
||||||
|
<strong>sortie standard</strong> et la <strong>sortie d'erreur</strong>.
|
||||||
|
</p>
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
<h3>Comportement par défaut</h3>
|
||||||
|
|
||||||
|
<p>
|
||||||
|
Pour résumer, chaque commande a donc :</p>
|
||||||
|
<ul>
|
||||||
|
<li> une <em>entrée standard</em>, </li>
|
||||||
|
<li> une <em>sortie standard</em> et </li>
|
||||||
|
<li> une <em>sortie d'erreur</em>.</li>
|
||||||
|
</ul>
|
||||||
|
|
||||||
|
<p> Par défaut, l'entrée standard est le clavier, la sortie standard est
|
||||||
|
l'écran, et la sortie d'erreur est aussi l'écran.</p>
|
||||||
|
|
||||||
|
<p> C'est sur le clavier que vous tapez ; ce que vous tapez et ce
|
||||||
|
que renvoient les programmes s'inscrit à l'écran ; les messages
|
||||||
|
d'erreur renvoyés par les programmes s'affichent à l'écran.
|
||||||
|
</p>
|
||||||
|
|
||||||
|
<h2>Les redirections</h2>
|
||||||
|
|
||||||
|
<p>
|
||||||
|
Mais il ne s'agit là que du comportement par défaut, et pas d'un
|
||||||
|
comportement obligatoire. Vous pouvez tout à fait orienter différemment
|
||||||
|
vos programmes.</p>
|
||||||
|
|
||||||
|
<p> Par exemple, si vous donnez une vache comme entrée au hachoir, vous
|
||||||
|
pouvez orienter la sortie vers une imprimante (au lieu de l'écran,
|
||||||
|
proposé par défaut), et vous imprimerez ainsi du steak haché. </p>
|
||||||
|
|
||||||
|
<p>
|
||||||
|
Ou encore, vous pouvez donner un plant de carottes comme entrée au
|
||||||
|
programme <code>cueillette</code>, et envoyer la sortie (c'est-à-dire
|
||||||
|
les carottes cueillies) au programme <code>hachoir</code>.
|
||||||
|
</p>
|
||||||
|
|
||||||
|
<p>
|
||||||
|
Nous allons étudier successivement :
|
||||||
|
</p>
|
||||||
|
|
||||||
|
<ul>
|
||||||
|
<li> comment rediriger la sortie d'une commande vers un
|
||||||
|
fichier ;</li>
|
||||||
|
|
||||||
|
<li> comment ajouter la sortie d'une commande à la fin d'un
|
||||||
|
fichier ;</li>
|
||||||
|
|
||||||
|
<li> comment utiliser un fichier comme entrée d'une commande ;</li>
|
||||||
|
|
||||||
|
<li> comment utiliser la sortie d'une commande comme entrée d'une
|
||||||
|
autre.</li>
|
||||||
|
</ul>
|
||||||
|
|
||||||
|
<p>
|
||||||
|
Ces différentes configurations esquissent la grammaire d'une utilisation
|
||||||
|
très performante des fonctionnalités du shell ; <strong>vous saurez
|
||||||
|
en effet comment brancher un fichier sur l'entrée ou sur la sortie d'une
|
||||||
|
commande, et comment brancher la sortie d'une commande sur l'entrée
|
||||||
|
d'une autre</strong>. Il n'y a pas d'autre combinaison possible.
|
||||||
|
</p>
|
||||||
|
|
||||||
|
|
||||||
|
<h3>Rediriger la sortie dans un fichier : <code>></code></h3>
|
||||||
|
|
||||||
|
<p>
|
||||||
|
On peut <em> rediriger</em> la sortie standard d'une commande vers un
|
||||||
|
fichier (caractère « <code>></code> »). Le résultat de la
|
||||||
|
commande sera placé dans le fichier au lieu de s'afficher sur l'écran.
|
||||||
|
Exemple :
|
||||||
|
</p>
|
||||||
|
|
||||||
|
<pre><span class="prompt">chaland ~ $</span> ls -l > foo</pre>
|
||||||
|
|
||||||
|
<p>
|
||||||
|
Le résultat de <code>ls -l</code> ne s'affiche pas à l'écran, mais il est placé
|
||||||
|
dans le fichier <code>foo</code>. On peut alors taper
|
||||||
|
</p>
|
||||||
|
|
||||||
|
<pre><span class="prompt">chaland ~ $</span> less foo</pre>
|
||||||
|
|
||||||
|
<p class="continue">
|
||||||
|
(ou <code>more foo</code>)
|
||||||
|
pour lire le fichier page par page.
|
||||||
|
</p>
|
||||||
|
|
||||||
|
|
||||||
|
<h3>Ajouter la sortie à un fichier : <code>>></code></h3>
|
||||||
|
|
||||||
|
<p> On veut parfois ajouter la sortie d'un programme à un fichier, sans
|
||||||
|
effacer ce qui précède. Or, par défaut, si l'on tape plusieurs fois
|
||||||
|
</p>
|
||||||
|
|
||||||
|
<pre><span class="prompt">chaland ~ $</span> ls -l > foo</pre>
|
||||||
|
|
||||||
|
<p class="continue">
|
||||||
|
à chaque fois, le contenu antérieur du fichier <code>foo</code> est
|
||||||
|
écrasé par le contenu ultérieur.
|
||||||
|
</p>
|
||||||
|
|
||||||
|
<p>
|
||||||
|
Pour éviter cela, il existe l'outil de redirection >>. Ainsi, si
|
||||||
|
vous tapez plusieurs fois
|
||||||
|
</p>
|
||||||
|
|
||||||
|
<pre><span class="prompt">chaland ~ $</span> ls -l >> foo</pre>
|
||||||
|
|
||||||
|
<p class="continue">
|
||||||
|
le fichier <code>foo</code> contiendra <em>à la suite</em> tout ce que
|
||||||
|
vous a renvoyé la commande.
|
||||||
|
</p>
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
<h3>Rediriger l'entrée : <code><</code></h3>
|
||||||
|
|
||||||
|
<p>
|
||||||
|
On peut aussi rediriger l'entrée standard d'une commande (caractère
|
||||||
|
« <code><</code> »). La commande lira alors le fichier au
|
||||||
|
lieu du clavier. Exemple :
|
||||||
|
</p>
|
||||||
|
|
||||||
|
<pre><span class="prompt">chaland ~ $</span> elm leroy < foo</pre>
|
||||||
|
|
||||||
|
<p class="continue">
|
||||||
|
envoie par mail à Xavier Leroy le résultat de la commande <code>ls -l</code> de
|
||||||
|
tout à l'heure.
|
||||||
|
</p>
|
||||||
|
|
||||||
|
<p>
|
||||||
|
On peut aussi taper <code>more < foo</code> qui est équivalent à
|
||||||
|
<code>more foo</code> car <code>more</code> sans argument lit son entrée
|
||||||
|
standard et l'affiche page par page sur le terminal.
|
||||||
|
</p>
|
||||||
|
|
||||||
|
<h3>Connecter la sortie d'une commande sur l'entrée d'une autre :
|
||||||
|
<code>|</code></h3>
|
||||||
|
|
||||||
|
<p>
|
||||||
|
Il devient rapidement ennuyeux de taper :
|
||||||
|
</p>
|
||||||
|
|
||||||
|
<pre><span class="prompt">chaland ~ $</span> ls -l > foo
|
||||||
|
<span class="prompt">chaland ~ $</span> less < foo
|
||||||
|
<span class="prompt">chaland ~ $</span> rm foo</pre>
|
||||||
|
|
||||||
|
<p>
|
||||||
|
On peut se passer du fichier intermédiaire (<code>foo</code> dans notre
|
||||||
|
exemple) grâce à un <em>pipe</em> (caractère
|
||||||
|
« <code>|</code> »). Un pipe connecte directement la sortie
|
||||||
|
standard d'une commande sur l'entrée standard d'une autre commande.
|
||||||
|
Exemple : pour afficher page par page la liste des fichiers du
|
||||||
|
répertoire courant, faire
|
||||||
|
</p>
|
||||||
|
|
||||||
|
<pre><span class="prompt">chaland ~ $</span> ls -l | less</pre>
|
||||||
|
|
||||||
|
<p>
|
||||||
|
Le pipe, ou tube, est d'un usage très courant, et rend beaucoup de
|
||||||
|
services.
|
||||||
|
</p>
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
<h2>Succès et erreur</h2>
|
||||||
|
|
||||||
|
<p>
|
||||||
|
On a parfois besoin de savoir si une commande a réussi ou non avant d'en
|
||||||
|
lancer une autre. Les indicateurs <code>&&</code> et
|
||||||
|
<code>||</code> permettent, respectivement, de lancer une commande si
|
||||||
|
(et seulement si) la précédente a réussi ou échoué.
|
||||||
|
</p>
|
||||||
|
|
||||||
|
<p>
|
||||||
|
Par exemple, si j'ai un fichier <code>foo</code>, j'obtiens :
|
||||||
|
</p>
|
||||||
|
|
||||||
|
<pre>
|
||||||
|
<span class="prompt">chaland ~ $</span> ls foo && echo "J'ai un fichier foo."
|
||||||
|
foo
|
||||||
|
J'ai un fichier foo.
|
||||||
|
</pre>
|
||||||
|
|
||||||
|
<p>
|
||||||
|
Si je n'ai pas de fichier <code>foo</code>, le message ne s'affiche
|
||||||
|
pas. En revanche, si je tape alors :
|
||||||
|
</p>
|
||||||
|
|
||||||
|
<pre>
|
||||||
|
<span class="prompt">chaland ~ $</span> ls foo || echo "Je n'ai pas de fichier foo."
|
||||||
|
ls: foo: No such file or directory
|
||||||
|
Je n'ai pas de fichier foo.
|
||||||
|
</pre>
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
<h2>Redirection des sorties standard et d'erreur</h2>
|
||||||
|
|
||||||
|
<p>
|
||||||
|
Il est parfois utile de rediriger la sortie standard et la sortie
|
||||||
|
d'erreur vers un même endroit. Pour cela, on utilise le motif
|
||||||
|
<code>2>&1</code> avant la redirection.
|
||||||
|
</p>
|
||||||
|
|
||||||
|
<table class="tableau">
|
||||||
|
<tr>
|
||||||
|
<th> Fonction </th>
|
||||||
|
<th> Bourne shell (sh, bash) </th>
|
||||||
|
<th> Z-shell (zsh) </th>
|
||||||
|
</tr>
|
||||||
|
<tr>
|
||||||
|
<td>Redirige la sortie d'erreur (2) et la sortie standard (1) sur l'entrée
|
||||||
|
de la commande suivante</td>
|
||||||
|
<td><code>2>&1 |</code></td>
|
||||||
|
<td><code> |&</code></td>
|
||||||
|
</tr>
|
||||||
|
<tr>
|
||||||
|
<td>Redirige la sortie d'erreur et la sortie standard dans un fichier</td>
|
||||||
|
<td><code>2>&1 ></code></td>
|
||||||
|
<td><code> >&</code></td>
|
||||||
|
</tr>
|
||||||
|
<tr>
|
||||||
|
<td>Redirige la sortie d'erreur et la sortie
|
||||||
|
standard à la fin d'un fichier existant</td>
|
||||||
|
<td><code>2>&1 >></code></td>
|
||||||
|
<td><code>>>&</code></td>
|
||||||
|
</tr>
|
||||||
|
</table>
|
||||||
|
|
||||||
|
<h3>Remarques</h3>
|
||||||
|
|
||||||
|
<p>
|
||||||
|
Normalement, une redirection avec <code>></code> sur un fichier qui
|
||||||
|
existe déjà efface le contenu du fichier avant d'y placer le résultat de la
|
||||||
|
commande. Les shells ont des options pour demander confirmation, ou
|
||||||
|
refuser d'effacer le fichier.
|
||||||
|
</p>
|
||||||
|
|
||||||
|
<p>
|
||||||
|
Une ligne de commandes contenant des <code>|</code> s'appelle un pipe-line.
|
||||||
|
Quelques commandes souvent utilisées dans les pipe-lines sont:
|
||||||
|
</p>
|
||||||
|
|
||||||
|
<ul>
|
||||||
|
<li><a href="fichiers.html#less">more</a> (ou <code>less</code>,
|
||||||
|
bien plus évolué) à la fin du pipe-line, affiche le résultat page par page,
|
||||||
|
pour laisser le temps de le lire.
|
||||||
|
</li>
|
||||||
|
<li><a href="divers.html#wc">wc</a> compte le nombre de
|
||||||
|
caractères, de mots et de lignes de son entrée.
|
||||||
|
</li>
|
||||||
|
<li><a href="chercher.html#grep">grep</a> cherche dans son
|
||||||
|
entre les lignes contenant un mot donné, et les écrit sur sa sortie.
|
||||||
|
</li>
|
||||||
|
<li><a href="&url.tuteurs;unix/exercices/enchainer.html#syst">sort</a> lit toutes les lignes
|
||||||
|
de son entrée, les trie, et les écrit dans l'ordre sur sa sortie. Par défaut
|
||||||
|
l'ordre est alphabétique.
|
||||||
|
</li>
|
||||||
|
<li><a href="fichiers.html#head">tail</a> écrit sur sa sortie
|
||||||
|
les dernières lignes de son entrée.
|
||||||
|
</li>
|
||||||
|
<li><a href="fichiers.html#head">head</a> écrit sur sa sortie
|
||||||
|
les premières lignes de son entrée.
|
||||||
|
</li>
|
||||||
|
<li><a href="fichiers.html#cat">cat</a> copie plusieurs fichiers
|
||||||
|
sur sa sortie.
|
||||||
|
</li>
|
||||||
|
<li><code>fold</code> coupe les lignes de son
|
||||||
|
entrée à 80 caractères et écrit le résultat sur sa sortie.
|
||||||
|
</li>
|
||||||
|
</ul>
|
||||||
|
|
||||||
|
<h3>Exemples</h3>
|
||||||
|
|
||||||
|
<pre>cat glop buz > toto</pre>
|
||||||
|
|
||||||
|
<p>
|
||||||
|
Concatène les fichiers <code>glop</code> et <code>buz</code> et place le
|
||||||
|
résultat dans <code>toto</code>.
|
||||||
|
</p>
|
||||||
|
|
||||||
|
<pre>wc -w /usr/dict/words</pre>
|
||||||
|
|
||||||
|
<p>
|
||||||
|
Affiche le nombre de mots du dictionnaire Unix.
|
||||||
|
</p>
|
||||||
|
|
||||||
|
<pre>grep gag /usr/dict/words | tail</pre>
|
||||||
|
|
||||||
|
<p>
|
||||||
|
Affiche les 10 derniers mots du dictionnaire qui contiennent la chaîne
|
||||||
|
<code>gag</code>.
|
||||||
|
</p>
|
||||||
|
|
||||||
|
<h2>Récapitulatif</h2>
|
||||||
|
|
||||||
|
<p>
|
||||||
|
La panoplie complète des redirections est la suivante :
|
||||||
|
</p>
|
||||||
|
|
||||||
|
<ul>
|
||||||
|
<li><code>></code> : change la sortie standard de la commande pour la placer
|
||||||
|
dans un fichier.
|
||||||
|
</li>
|
||||||
|
<li><code><</code> : change l'entrée standard de la commande pour la prendre
|
||||||
|
dans un fichier.
|
||||||
|
</li>
|
||||||
|
<li><code>|</code> : branche la sortie standard de la commande de gauche sur
|
||||||
|
l'entrée standard de la commande de droite.
|
||||||
|
</li>
|
||||||
|
<li><code>>></code> : change la sortie standard pour l'ajouter à la fin
|
||||||
|
d'un fichier existant.
|
||||||
|
</li>
|
||||||
|
<li><code>||</code> : exécuter la commande suivante si la première a
|
||||||
|
échoué.
|
||||||
|
</li>
|
||||||
|
<li><code>&&</code> : n'exécuter la commande suivante que si la
|
||||||
|
première a réussi.
|
||||||
|
</li>
|
||||||
|
</ul>
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
<p>Vous êtes maintenant en mesure de faire ces <a
|
||||||
|
href="&url.tuteurs;unix/exercices/">exercices</a> pour vous
|
||||||
|
entraîner.</p>
|
||||||
|
|
||||||
|
|
||||||
|
<div class="metainformation">
|
||||||
|
Basé sur un polycopié de Roberto Di Cosmo, Xavier Leroy et Damien Doligez.
|
||||||
|
Modifications : Nicolas George, Baptiste Mélès.
|
||||||
|
Dernière modification le <date value="$Date: 2005-05-31 11:33:38 $" />.
|
||||||
|
</div>
|
||||||
|
|
||||||
|
</body>
|
||||||
|
</html>
|
220
unix/shell/index.tml
Normal file
220
unix/shell/index.tml
Normal file
|
@ -0,0 +1,220 @@
|
||||||
|
<?xml version="1.0" encoding="ISO-8859-1"?>
|
||||||
|
<!DOCTYPE html
|
||||||
|
PUBLIC "-//ENS/Tuteurs//DTD TML 1//EN"
|
||||||
|
"tuteurs://DTD/tml.dtd">
|
||||||
|
<html>
|
||||||
|
<head>
|
||||||
|
<title>Shell</title>
|
||||||
|
</head>
|
||||||
|
<body>
|
||||||
|
|
||||||
|
<h1>Présentation du shell</h1>
|
||||||
|
|
||||||
|
<p>
|
||||||
|
Le mot <em>shell</em> signifie « coquille » en anglais. Il
|
||||||
|
s'agit du programme que vous utilisez régulièrement sur les machines
|
||||||
|
Unix de l'ENS (que ce soient les Sun, les PC sous FreeBSD ou autres
|
||||||
|
dérivés d'Unix), et qui interprète les commandes. Par exemple, vous y
|
||||||
|
tapez <code>pine</code> ou <code>mutt</code>, <code>forum</code>,
|
||||||
|
<code>cc</code>, <code>mozilla</code>, etc.
|
||||||
|
</p>
|
||||||
|
|
||||||
|
<p>
|
||||||
|
Mais quel rapport avec une coquille ? Eh bien, dans une coquille
|
||||||
|
vous pouvez mettre de l'eau, pour la porter ensuite à votre
|
||||||
|
bouche ; vous pouvez y mettre du sable avant de le verser dans des
|
||||||
|
bocaux ; en somme, une coquille est un récipient qui permet
|
||||||
|
de manipuler toutes sortes de contenus. Il en va de même du shell. C'est
|
||||||
|
un outil en mode texte qui permet l'exploitation d'un grand nombre de
|
||||||
|
ressources de l'ordinateur.
|
||||||
|
</p>
|
||||||
|
|
||||||
|
<p>
|
||||||
|
Cette page vous donnera les rudiments pour exploiter les deux
|
||||||
|
principales fonctionnalités du shell :
|
||||||
|
</p>
|
||||||
|
|
||||||
|
<ul>
|
||||||
|
<li> l'usage interactif, reposant sur les <strong>lignes de
|
||||||
|
commandes</strong> ;</li>
|
||||||
|
<li> la conception de <strong>scripts</strong> (programmes écrits en
|
||||||
|
shell). </li>
|
||||||
|
</ul>
|
||||||
|
|
||||||
|
|
||||||
|
<h2><a name="etats">Les deux états du shell</a>
|
||||||
|
</h2>
|
||||||
|
|
||||||
|
<p>
|
||||||
|
Le shell, comme le normalien, ne connaît que deux états :
|
||||||
|
</p>
|
||||||
|
|
||||||
|
<ul>
|
||||||
|
<li> le travail ;</li>
|
||||||
|
<li> l'inactivité.</li>
|
||||||
|
</ul>
|
||||||
|
|
||||||
|
<p>
|
||||||
|
Le shell, une fois lancé, est inactif : il attend qu'on lui donne
|
||||||
|
des ordres. Quand on lui en donne un, il l'exécute ; et quand il a
|
||||||
|
terminé, il retourne à son état d'inactivité, en attente d'un nouveau
|
||||||
|
commandement.
|
||||||
|
</p>
|
||||||
|
|
||||||
|
<p>
|
||||||
|
Quand le shell est inactif, il affiche une <em>invite</em>
|
||||||
|
(<em>prompt</em> en anglais), qui ressemble à cela :
|
||||||
|
</p>
|
||||||
|
|
||||||
|
<pre>
|
||||||
|
<span class="prompt">chaland ~ $</span>
|
||||||
|
</pre>
|
||||||
|
|
||||||
|
<p>
|
||||||
|
Un curseur, parfois clignotant, indique que le shell attend que vous lui
|
||||||
|
tapiez des instructions.
|
||||||
|
</p>
|
||||||
|
|
||||||
|
<h2><a name="path">Comment le shell trouve-t-il les commandes ?</a>
|
||||||
|
</h2>
|
||||||
|
|
||||||
|
<h3>L'ordre de recherche</h3>
|
||||||
|
|
||||||
|
<p>
|
||||||
|
J'ai l'habitude de taper des commandes dans le shell, et je vois qu'il
|
||||||
|
réagit. Mais comment comprend-il ce que je veux faire ?
|
||||||
|
</p>
|
||||||
|
|
||||||
|
<p>
|
||||||
|
Prenons un cas simple. Je tape la commande <code>bonjour</code> à
|
||||||
|
l'invite (<em>prompt</em>) du shell. Il va chercher à plusieurs endroits
|
||||||
|
ce que j'entends par là :
|
||||||
|
</p>
|
||||||
|
|
||||||
|
<ol>
|
||||||
|
<li> d'abord, il va se demander si <code>bonjour</code> n'est pas une de
|
||||||
|
ses commandes intégrées ; si c'est le cas, il l'exécute
|
||||||
|
directement, sinon il passe à l'étape suivante ;</li>
|
||||||
|
<li> ensuite, il va lire le contenu d'une variable, qui s'appelle
|
||||||
|
<code>PATH</code>, et qui indique le « chemin » où trouver les
|
||||||
|
commandes que l'on appelle. Par exemple, si la variable PATH contient
|
||||||
|
les répertoires :
|
||||||
|
<ul>
|
||||||
|
<li> <code>/usr/bin</code> </li>
|
||||||
|
<li> <code>/bin</code> et </li>
|
||||||
|
<li> <code>/home/toto/bin</code>,</li>
|
||||||
|
</ul>
|
||||||
|
alors le shell va chercher successivement les commandes :
|
||||||
|
<ul>
|
||||||
|
<li> <code>/usr/bin/bonjour</code>,</li>
|
||||||
|
<li> <code>/bin/bonjour</code> et </li>
|
||||||
|
<li> <code>/home/toto/bin/bonjour</code> ;</li>
|
||||||
|
</ul></li>
|
||||||
|
<li> enfin, s'il ne trouve la commande dans aucun des répertoires
|
||||||
|
référencés par le <code>PATH</code>, il va renvoyer un message d'erreur
|
||||||
|
en disant que désolé, il ne voit pas ce que l'on entend par
|
||||||
|
<code>bonjour</code>. Exemple :
|
||||||
|
|
||||||
|
<pre>
|
||||||
|
<span class="prompt">chaland ~ $</span> bonjour
|
||||||
|
bonjour: Command not found</pre> </li>
|
||||||
|
</ol>
|
||||||
|
|
||||||
|
<p> La <a href="#variables">variable</a> <code>PATH</code> consiste en
|
||||||
|
une liste de répertoires séparés par des
|
||||||
|
« <code>:</code> ». Si vous voulez voir à quoi ressemble votre
|
||||||
|
PATH, tapez :
|
||||||
|
</p>
|
||||||
|
|
||||||
|
<pre>
|
||||||
|
<span class="prompt">chaland ~ $</span> echo $PATH</pre>
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
<h3><a name="builtins">Les commandes internes</a></h3>
|
||||||
|
|
||||||
|
<p>
|
||||||
|
Certaines commandes du shell ne sont pas des programmes mais des
|
||||||
|
commandes <em>internes</em> (<em>builtins functions</em>). Comme nous
|
||||||
|
l'avons vu, elles sont directement reconnues et exécutées par le shell.
|
||||||
|
Un exemple de commande interne est <code>cd</code> ; elle modifie
|
||||||
|
le répertoire courant du shell.
|
||||||
|
</p>
|
||||||
|
|
||||||
|
<div class="attention">
|
||||||
|
<p>
|
||||||
|
Attention : si vous créez un script (c'est-à-dire un programme
|
||||||
|
écrit en langage shell) qui utilise <code>cd</code>, il ne modifie pas
|
||||||
|
le répertoire courant du shell qui lance ce script, mais celui d'un
|
||||||
|
shell qui est créé à l'occasion de l'exécution de ce script, et qui
|
||||||
|
meurt à la fin de cette exécution.</p>
|
||||||
|
|
||||||
|
<p> Exemple : je crée un script <code>aller</code> qui contient les
|
||||||
|
lignes suivantes : </p>
|
||||||
|
|
||||||
|
<pre>
|
||||||
|
#! /bin/sh
|
||||||
|
cd $*</pre>
|
||||||
|
|
||||||
|
<p>
|
||||||
|
Nous aurons alors :
|
||||||
|
</p>
|
||||||
|
|
||||||
|
<pre>
|
||||||
|
<span class="prompt">chaland ~ $</span> aller toto
|
||||||
|
<span class="prompt">chaland ~ $</span> cd toto
|
||||||
|
<span class="prompt">chaland ~/toto $</span></pre>
|
||||||
|
|
||||||
|
</div>
|
||||||
|
|
||||||
|
|
||||||
|
<h2><a name="prog">Quels programmes utilisent le langage du shell ?</a></h2>
|
||||||
|
|
||||||
|
<h3>Les scripts shell</h3>
|
||||||
|
<p>
|
||||||
|
La répétition de commandes complexes en ligne de commande du shell est
|
||||||
|
rapidement fastidieuse ; aussi est-il très pratique de connaître
|
||||||
|
les bases de la programmation de scripts shell. Les scripts servent à
|
||||||
|
automatiser ou systématiser des tâches.
|
||||||
|
</p>
|
||||||
|
|
||||||
|
|
||||||
|
<h3>Le script <code>.profile</code></h3>
|
||||||
|
<p>
|
||||||
|
Il existe un script spécial, qui est exécuté au moment où on se connecte. Ce
|
||||||
|
script est contenu dans le fichier <code>$HOME/.profile</code>. C'est ce
|
||||||
|
fichier qui vous dit s'il y a de nouveaux messages dans forum, si vous avez
|
||||||
|
du courrier, etc.
|
||||||
|
</p>
|
||||||
|
|
||||||
|
<p>
|
||||||
|
Ce fichier est normalement mis à jour automatiquement par les scripts de la
|
||||||
|
config conscrits. Il est néanmoins possible de le modifier pour changer des
|
||||||
|
options.
|
||||||
|
</p>
|
||||||
|
|
||||||
|
<h3>Le script <code>.xinitrc</code></h3>
|
||||||
|
<p> Il existe encore le script <code>.xinitrc</code>, qui lance X ;
|
||||||
|
X est le gestionnaire de fenêtres classique sous Unix.
|
||||||
|
</p>
|
||||||
|
|
||||||
|
|
||||||
|
<h3>Créer ses propres scripts</h3>
|
||||||
|
<p>
|
||||||
|
Le nombre de scripts possibles est illimité ; vous pouvez en créer
|
||||||
|
autant que vous voulez, selon vos besoins : c'est ainsi que l'on
|
||||||
|
personnalise son système et qu'on l'adapte à ses exigences, plutôt que
|
||||||
|
l'inverse.
|
||||||
|
</p>
|
||||||
|
|
||||||
|
|
||||||
|
<div class="metainformation">
|
||||||
|
Basé sur un polycopié de Roberto Di Cosmo, Xavier Leroy et Damien
|
||||||
|
Doligez.
|
||||||
|
Modifications : Nicolas George, Baptiste Mélès.
|
||||||
|
Dernière modification le <date value="$Date: 2005-05-31 11:33:38 $"
|
||||||
|
/>.
|
||||||
|
</div>
|
||||||
|
|
||||||
|
</body>
|
||||||
|
</html>
|
452
unix/shell/script.tml
Normal file
452
unix/shell/script.tml
Normal file
|
@ -0,0 +1,452 @@
|
||||||
|
<?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>Rendre un script exécutable</h3>
|
||||||
|
|
||||||
|
<p> Pour être un script, un fichier 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="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="index.html">page principale sur le 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><a name="structures">Structures de contrôle</a></h2>
|
||||||
|
|
||||||
|
<p>
|
||||||
|
C'est avec les structures de contrôle qu'un programme peut commencer à
|
||||||
|
devenir sérieux. Le principe général de ces structures est le
|
||||||
|
suivant : adapter le comportement du programme selon les réponses
|
||||||
|
apportées à certaines questions.
|
||||||
|
</p>
|
||||||
|
|
||||||
|
<p>
|
||||||
|
Nous avons déjà vu une application possible des structures de contrôle
|
||||||
|
en parlant des variables. Le programme <code>hachoir</code> conçu par
|
||||||
|
Robert le jardinier pose la question suivante : est-ce que
|
||||||
|
<code>$USER</code> vaut « Robert » ?
|
||||||
|
</p>
|
||||||
|
|
||||||
|
<ul>
|
||||||
|
<li> si oui, alors le hachoir doit se mettre en marche ;</li>
|
||||||
|
<li> si non, alors le hachoir doit refuser de se mettre en
|
||||||
|
marche.</li>
|
||||||
|
</ul>
|
||||||
|
|
||||||
|
|
||||||
|
<h3>La boucle <code>if</code></h3>
|
||||||
|
|
||||||
|
<p>
|
||||||
|
La structure de contrôle <code>if</code> est la plus courante de toutes,
|
||||||
|
et la plus élémentaire. Elle est constituée de quatre termes :</p>
|
||||||
|
|
||||||
|
<ol>
|
||||||
|
<li> <code>if</code> (si), qui marque la condition à remplir ;
|
||||||
|
</li>
|
||||||
|
<li> <code>then</code> (alors), qui marque les conséquences si la
|
||||||
|
condition est remplie ; </li>
|
||||||
|
<li> <code>else</code> (sinon), qui est facultatif et marque le
|
||||||
|
comportement à adopter si la condition n'est pas remplie ; </li>
|
||||||
|
<li> <code>fi</code> (<code>if</code> à l'envers), qui marque la fin de
|
||||||
|
la boucle.</li>
|
||||||
|
</ol>
|
||||||
|
|
||||||
|
<pre>if <em>commande</em> ; then <em>commandes</em> ; else <em>commandes</em> ; fi</pre>
|
||||||
|
|
||||||
|
<p class="continue"> ou bien (car le point et virgule équivaut à un saut
|
||||||
|
de ligne) :</p>
|
||||||
|
|
||||||
|
<pre>if <em>commande</em>
|
||||||
|
then <em>commandes</em>
|
||||||
|
else <em>commandes</em>
|
||||||
|
fi</pre>
|
||||||
|
|
||||||
|
<p>
|
||||||
|
Par exemple, pour Robert le jardinier, on aura :
|
||||||
|
</p>
|
||||||
|
|
||||||
|
<pre>if test $USER = Robert
|
||||||
|
then hacher_menu_comme_chair_à_pâté $*
|
||||||
|
else echo "Quand tu seras grand, $USER."
|
||||||
|
echo "Et fais bien attention en traversant la rue."
|
||||||
|
fi</pre>
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
<h3>La boucle <code>for</code></h3>
|
||||||
|
|
||||||
|
<p>
|
||||||
|
La boucle <code>for</code> affecte successivement une variable chaque
|
||||||
|
chaîne de caractères trouvée dans une <em>liste de chaînes</em>, et
|
||||||
|
exécute les <em>commandes</em> une fois pour chaque chaîne.
|
||||||
|
</p>
|
||||||
|
|
||||||
|
<pre>for <em>var</em> in <em>liste de chaînes</em> ; do <em>commandes</em> ; done</pre>
|
||||||
|
|
||||||
|
<p class="continue"> ou bien :</p>
|
||||||
|
|
||||||
|
<pre>for <em>var</em> in <em>liste de chaînes</em>
|
||||||
|
do <em>commandes</em>
|
||||||
|
done</pre>
|
||||||
|
|
||||||
|
|
||||||
|
<p>
|
||||||
|
Rappel : <code>$<em>var</em></code> accède à la valeur courante de
|
||||||
|
<em>var</em>. La partie <em>commandes</em> est une suite de commandes,
|
||||||
|
séparées par des points et virgules (<code>;</code>) ou des retours à la
|
||||||
|
ligne.
|
||||||
|
</p>
|
||||||
|
|
||||||
|
<p>
|
||||||
|
Exemple :
|
||||||
|
</p>
|
||||||
|
|
||||||
|
<pre>for i in *; do echo "$i"; done</pre>
|
||||||
|
|
||||||
|
<p class="continue">
|
||||||
|
affiche les noms de tous les fichiers du répertoire courant, un par ligne.
|
||||||
|
</p>
|
||||||
|
|
||||||
|
<p>
|
||||||
|
Remarque : plus un programme grossit, plus il importe que son
|
||||||
|
contenu soit lisible. <strong>Les noms de variable doivent donc être le
|
||||||
|
plus lisibles possible</strong>, pour permettre à d'autres gens, ou bien
|
||||||
|
à vous-même dans quelques mois, de comprendre rapidement votre script.
|
||||||
|
Ainsi, il peut être plus explicite d'écrire, au lieu de « <code>for
|
||||||
|
i in *; do echo "$i"; done</code> » :
|
||||||
|
</p>
|
||||||
|
|
||||||
|
<pre>for fichier in *; do echo "$fichier"; done</pre>
|
||||||
|
|
||||||
|
<p>
|
||||||
|
En outre, pour des raisons de lisibilité, <strong>n'hésitez pas à
|
||||||
|
gaspiller des lignes de code</strong> en sautant des lignes ; les
|
||||||
|
lignes de code ne sont pas une ressource rare :
|
||||||
|
</p>
|
||||||
|
|
||||||
|
<pre>for fichier in *
|
||||||
|
do echo "$fichier"
|
||||||
|
done</pre>
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
<h3>La boucle <code>while</code></h3>
|
||||||
|
|
||||||
|
<pre>while <em>commande</em>
|
||||||
|
do <em>commande</em>
|
||||||
|
done</pre>
|
||||||
|
|
||||||
|
<p>
|
||||||
|
La boucle <code>while</code> exécute les <em>commandes</em> de manière
|
||||||
|
répétée tant que la première <em>commande</em> réussit.</p>
|
||||||
|
|
||||||
|
<p> Par exemple : <em>tant que</em> le mot de passe correct n'a pas
|
||||||
|
été donné, refuser l'accès et redemander le mot de passe.
|
||||||
|
</p>
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
<h3>La boucle <code>case</code></h3>
|
||||||
|
|
||||||
|
<pre>case <em>chaîne</em> in
|
||||||
|
<em>pattern</em>) <em>commande</em> ;;
|
||||||
|
<em>pattern</em>) <em>commande</em> ;;
|
||||||
|
esac</pre>
|
||||||
|
|
||||||
|
<p>
|
||||||
|
La boucle <code>case</code> exécute la première <em>commande</em> telle
|
||||||
|
que la <em>chaîne</em> est de la forme <em>pattern</em>. Un
|
||||||
|
<em>pattern</em> (motif) est un mot contenant éventuellement les
|
||||||
|
constructions <code>*</code>, <code>?</code>, <code>[a-d]</code>, avec
|
||||||
|
la même signification que pour les raccourcis dans les noms de
|
||||||
|
fichiers. Exemple :
|
||||||
|
</p>
|
||||||
|
|
||||||
|
<pre>
|
||||||
|
case $var in
|
||||||
|
[0-9]*) echo 'Nombre';;
|
||||||
|
[a-zA-Z]*) echo 'Mot';;
|
||||||
|
*) echo 'Autre chose';;
|
||||||
|
esac</pre>
|
||||||
|
|
||||||
|
<p>
|
||||||
|
Vous observerez que l'on clôt la boucle <code>case</code> avec
|
||||||
|
<code>esac</code>, qui est le mot <code>case</code> à l'envers, de même
|
||||||
|
que l'on clôt <code>if</code> avec <code>fi</code>.
|
||||||
|
</p>
|
||||||
|
|
||||||
|
<h2><a name="retour">Code de retour</a></h2>
|
||||||
|
|
||||||
|
<p>
|
||||||
|
On remarque que la condition des commandes <code>if</code> et
|
||||||
|
<code>while</code> est une commande. Chaque commande renvoie un code de
|
||||||
|
retour (qui est ignoré en utilisation normale). Si le code est 0, la
|
||||||
|
commande a réussi ; sinon, la commande a échoué. Par exemple, le
|
||||||
|
compilateur <code>cc</code> renvoie un code d'erreur non nul si le
|
||||||
|
fichier compilé contient des erreurs, ou s'il n'existe pas.
|
||||||
|
</p>
|
||||||
|
|
||||||
|
<p>
|
||||||
|
Les commandes <code>if</code> et <code>while</code> considèrent donc le
|
||||||
|
code de retour 0 comme « vrai », et tout autre code comme
|
||||||
|
« faux ».
|
||||||
|
</p>
|
||||||
|
|
||||||
|
<p>
|
||||||
|
Il existe une commande <code>test</code>, qui évalue des expressions
|
||||||
|
booléennes (c'est-à-dire dont la valeur ne peut être que vraie ou
|
||||||
|
fausse, 1 ou 0) passées en argument, et renvoie un code de retour en
|
||||||
|
fonction du résultat. Elle est bien utile pour les scripts.
|
||||||
|
Exemple :
|
||||||
|
</p>
|
||||||
|
|
||||||
|
<pre>
|
||||||
|
if test $var = foo
|
||||||
|
then echo 'La variable vaut foo'
|
||||||
|
else echo 'La variable ne vaut pas foo'
|
||||||
|
fi</pre>
|
||||||
|
|
||||||
|
|
||||||
|
<p>Vous êtes maintenant en mesure de faire ces <a
|
||||||
|
href="&url.tuteurs;unix/exercices/">exercices</a> pour vous
|
||||||
|
entraîner.</p>
|
||||||
|
|
||||||
|
|
||||||
|
<div class="metainformation">
|
||||||
|
Basé sur un polycopié de Roberto Di Cosmo, Xavier Leroy et Damien Doligez.
|
||||||
|
Modifications : Nicolas George, Baptiste Mélès.
|
||||||
|
Dernière modification le <date value="$Date: 2005-05-31 11:33:38 $" />.
|
||||||
|
</div>
|
||||||
|
|
||||||
|
</body>
|
||||||
|
</html>
|
225
unix/shell/variable.tml
Normal file
225
unix/shell/variable.tml
Normal file
|
@ -0,0 +1,225 @@
|
||||||
|
<?xml version="1.0" encoding="ISO-8859-1"?>
|
||||||
|
<!DOCTYPE html
|
||||||
|
PUBLIC "-//ENS/Tuteurs//DTD TML 1//EN"
|
||||||
|
"tuteurs://DTD/tml.dtd">
|
||||||
|
<html>
|
||||||
|
<head>
|
||||||
|
<title>Variables</title>
|
||||||
|
</head>
|
||||||
|
<body>
|
||||||
|
|
||||||
|
<h1><a name="variables">Les variables en shell</a></h1>
|
||||||
|
|
||||||
|
<h2>Qu'est-ce qu'une variable ?</h2>
|
||||||
|
|
||||||
|
<p>
|
||||||
|
Une variable est l'assignation d'une étiquette à un contenu ; ce
|
||||||
|
contenu, comme l'indique le mot « variable », peut changer
|
||||||
|
autant que l'on veut ; l'assignation de l'étiquette à ce contenu,
|
||||||
|
elle, est fixe, aussi longtemps que l'on ne dissout pas la
|
||||||
|
variable. </p>
|
||||||
|
|
||||||
|
<p>
|
||||||
|
La notion de variable est commune à presque tous les langages
|
||||||
|
informatiques, et en particulier aux langages de programmation. Ceux qui
|
||||||
|
ont déjà manipulé des langages sont donc familiers avec cette
|
||||||
|
notion. Pour les autres, un petit exemple les aidera peut-être à la
|
||||||
|
saisir.
|
||||||
|
</p>
|
||||||
|
|
||||||
|
<p>
|
||||||
|
Mettons que vous programmiez un hachoir, comme nous le proposions sur la
|
||||||
|
page consacrée au <a href="commande.html">shell en ligne de
|
||||||
|
commande</a>. Un hachoir est un instrument dangereux, à ne pas mettre
|
||||||
|
à la portée des enfants. Robert le jardinier, qui a conçu ce
|
||||||
|
hachoir, veut être le seul à pouvoir l'utiliser, sans quoi le
|
||||||
|
petit Émile pourrait se blesser en y mettant le doigt.</p>
|
||||||
|
|
||||||
|
<p> Ainsi, il va dire au programme <code>hachoir</code> de vérifier la
|
||||||
|
variable <code>USER</code>, qui contient le nom de l'utilisateur. Si le
|
||||||
|
nom « Robert » est associé à l'étiquette <code>USER</code>,
|
||||||
|
alors le programme se met en route ; sinon, il dit à l'utilisateur
|
||||||
|
de ne pas utiliser cet instrument sans la présence d'un adulte, et de
|
||||||
|
bien regarder des deux côtés avant de traverser la rue.
|
||||||
|
</p>
|
||||||
|
|
||||||
|
<p>
|
||||||
|
Certaines variables sont prédéfinies, par exemple
|
||||||
|
<code>USER</code> ; mais on peut en créer autant que l'on veut. Par
|
||||||
|
exemple, si Robert veut autoriser d'autres adultes que lui à utiliser
|
||||||
|
son hachoir, il peut faire que le programme demande à l'utilisateur quel
|
||||||
|
âge il a ; la réponse est enregistrée dans la variable
|
||||||
|
<code>age</code> ; ensuite, le programme va examiner le contenu de
|
||||||
|
cette variable. Si <code>age >= 18</code>, alors le hachoir peut se
|
||||||
|
mettre en route ; mais si <code>age < 18</code>, le hachoir
|
||||||
|
refuse de se mettre en marche.
|
||||||
|
</p>
|
||||||
|
|
||||||
|
<h2>Les variables en shell</h2>
|
||||||
|
|
||||||
|
<p>
|
||||||
|
En shell, pour désigner le contenu d'une variable, on écrit le nom de la
|
||||||
|
variable précédé du signe dollar. Exemple : <code>echo
|
||||||
|
$HOME</code> affiche le nom du répertoire personnel de l'utilisateur,
|
||||||
|
mémorisé par la variable <code>HOME</code>.
|
||||||
|
</p>
|
||||||
|
|
||||||
|
<h3>Les noms de variables</h3>
|
||||||
|
|
||||||
|
<p>
|
||||||
|
Par convention, les variables relevant du système, comme
|
||||||
|
<code>HOME</code>, <code>USER</code> et beaucoup d'autres, sont en
|
||||||
|
majuscules, tandis que l'on recommande d'écrire en minuscules les
|
||||||
|
variables que l'on se crée soi-même. On évite ainsi la désagréable
|
||||||
|
surprise de remplacer une variable importante et de casser tout ou
|
||||||
|
partie de son système.
|
||||||
|
</p>
|
||||||
|
|
||||||
|
<p>
|
||||||
|
Les noms de variables sont en effet sensibles à la casse :
|
||||||
|
<code>USER</code>, <code>user</code>, <code>User</code>,
|
||||||
|
<code>uSeR</code> etc. sont des variables différentes.
|
||||||
|
</p>
|
||||||
|
|
||||||
|
|
||||||
|
<h3>Définir une variable</h3>
|
||||||
|
|
||||||
|
<p>
|
||||||
|
La façon de donner une valeur à une variable varie selon le type de shell
|
||||||
|
utilisé :
|
||||||
|
</p>
|
||||||
|
|
||||||
|
<p>
|
||||||
|
<strong>C-Shell</strong> (<code>csh</code>, <code>tcsh</code>,
|
||||||
|
<code>lcsh</code>) : on utilise la commande <code>setenv</code> :
|
||||||
|
</p>
|
||||||
|
|
||||||
|
<pre>
|
||||||
|
<span class="prompt">chaland ~ $</span> setenv foo bar
|
||||||
|
<span class="prompt">chaland ~ $</span> echo $foo
|
||||||
|
bar</pre>
|
||||||
|
|
||||||
|
<p>
|
||||||
|
Famille des <strong>Bourne Shell</strong> (<code>sh</code>, <code>bash</code>,
|
||||||
|
<code>zsh</code>, <code>ksh</code>) : on utilise <code>export</code> :
|
||||||
|
</p>
|
||||||
|
|
||||||
|
<pre>
|
||||||
|
<span class="prompt">chaland ~ $</span> foo=bar
|
||||||
|
<span class="prompt">chaland ~ $</span> export foo
|
||||||
|
<span class="prompt">chaland ~ $</span> echo $foo
|
||||||
|
bar</pre>
|
||||||
|
|
||||||
|
<div class="attention">
|
||||||
|
Comme vous pouvez le remarquer :
|
||||||
|
|
||||||
|
<ul>
|
||||||
|
|
||||||
|
<li> pour <strong>définir</strong> le contenu d'une variable, on
|
||||||
|
écrit simplement son nom, <strong>sans le
|
||||||
|
signe $</strong> ;</li>
|
||||||
|
|
||||||
|
<li> tandis que pour <strong>utiliser</strong> le contenu d'une
|
||||||
|
variable, on fait précéder son nom du
|
||||||
|
<strong>signe $</strong>. </li>
|
||||||
|
|
||||||
|
</ul>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
|
||||||
|
<h3>Les variables d'environnement</h3>
|
||||||
|
|
||||||
|
<p>
|
||||||
|
Les valeurs des variables sont accessibles aux commandes lancées par le
|
||||||
|
shell. L'ensemble de ces valeurs constitue l'<em>environnement</em>.
|
||||||
|
On peut aussi supprimer une variable de l'environnement avec
|
||||||
|
<code>unsetenv</code> (C-Shell) ou <code>unset</code> (Bourne Shell).
|
||||||
|
</p>
|
||||||
|
|
||||||
|
<p>
|
||||||
|
Quelques variables d'environnement:
|
||||||
|
</p>
|
||||||
|
|
||||||
|
<ul>
|
||||||
|
<li><code>DISPLAY</code> : L'écran sur lequel les programmes X
|
||||||
|
travaillent. Cette variable est souvent de la forme :
|
||||||
|
<code>machine.somehost.somewhere:0.0</code> Si cette variable est vide,
|
||||||
|
c'est qu'il n'y a pas d'affichage graphique possible. </li>
|
||||||
|
<li><code>PRINTER</code> : pour les commandes d'impression. Contient le
|
||||||
|
nom de l'imprimante sur laquelle il faut envoyer vos fichiers. </li>
|
||||||
|
<li><code>EDITOR</code> : utilisée par <code>mutt</code>,
|
||||||
|
<code>forum</code>, et beaucoup d'autres commandes. Contient le nom de
|
||||||
|
votre éditeur de textes préféré. </li>
|
||||||
|
<li><code>VISUAL</code> : la même chose qu'<code>EDITOR</code>. </li>
|
||||||
|
<li><code>SHELL</code> : contient le nom de votre shell. </li>
|
||||||
|
<li><code>HOME</code> : contient le nom de votre répertoire personnel.
|
||||||
|
</li>
|
||||||
|
<li><code>USER</code> : contient votre nom de login. </li>
|
||||||
|
<li><code>LOGNAME</code> : la même chose que <code>USER</code>. </li>
|
||||||
|
<li><code>PATH</code> : contient une liste de répertoires dans lesquels
|
||||||
|
le shell va chercher les commandes.
|
||||||
|
</li>
|
||||||
|
</ul>
|
||||||
|
|
||||||
|
<p>
|
||||||
|
Exercice : Assurez-vous que <code>/usr/local/games/bin</code> se trouve
|
||||||
|
bien dans votre PATH.
|
||||||
|
</p>
|
||||||
|
|
||||||
|
<h2><a name="shvariables">Utiliser les variables dans un script</a></h2>
|
||||||
|
|
||||||
|
<p>
|
||||||
|
Dans les scripts, on peut utiliser des variables définies à l'extérieur
|
||||||
|
(avec <code>setenv</code> ou <code>export</code>), mais aussi définir ses
|
||||||
|
variables locales propres au script. On donne une valeur à une variable avec
|
||||||
|
une commande de la forme
|
||||||
|
<code><em>nom-de-variable</em>=<em>valeur</em></code>. Les variables sont
|
||||||
|
utilisées pour stocker des informations.
|
||||||
|
</p>
|
||||||
|
|
||||||
|
<p>
|
||||||
|
On a aussi des variables spéciales, initialisées automatiquement au
|
||||||
|
début du script:
|
||||||
|
</p>
|
||||||
|
|
||||||
|
<table class="tableau">
|
||||||
|
<tr>
|
||||||
|
<td><code>$0</code></td>
|
||||||
|
<td>Le nom de la commande (i.e. : du script)</td>
|
||||||
|
</tr>
|
||||||
|
<tr>
|
||||||
|
<td><code>$1</code>, <code>$2</code>, etc.</td>
|
||||||
|
<td>Le premier, deuxième, etc, argument passés au script.</td>
|
||||||
|
</tr>
|
||||||
|
<tr>
|
||||||
|
<td><code>$*</code></td>
|
||||||
|
<td>La liste de tous les arguments passés au script.</td>
|
||||||
|
</tr>
|
||||||
|
<tr>
|
||||||
|
<td><code>$#</code></td>
|
||||||
|
<td>Le nombre d'arguments passés au script.</td>
|
||||||
|
</tr>
|
||||||
|
<tr>
|
||||||
|
<td><code>$?</code></td>
|
||||||
|
<td>Le code de retour de la dernière commande lancée.</td>
|
||||||
|
</tr>
|
||||||
|
<tr>
|
||||||
|
<td><code>$!</code> </td>
|
||||||
|
<td>Le numéro de process de la dernière commande lancée en tâche de fond.</td>
|
||||||
|
</tr>
|
||||||
|
<tr>
|
||||||
|
<td><code>$$</code></td>
|
||||||
|
<td>Le numéro de process du shell lui-même.</td>
|
||||||
|
</tr>
|
||||||
|
</table>
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
<div class="metainformation">
|
||||||
|
Basé sur un polycopié de Roberto Di Cosmo, Xavier Leroy et Damien Doligez.
|
||||||
|
Modifications : Nicolas George, Baptiste Mélès.
|
||||||
|
Dernière modification le <date value="$Date: 2005-05-31 11:33:38 $" />.
|
||||||
|
</div>
|
||||||
|
|
||||||
|
</body>
|
||||||
|
</html>
|
Loading…
Reference in a new issue