tuteurs.ens.fr/unix/shell/commande.tml
2005-09-07 23:00:03 +00:00

511 lines
17 KiB
XML
Raw Blame History

This file contains invisible Unicode characters

This file contains invisible Unicode characters that are indistinguishable to humans but may be processed differently by a computer. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

<?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&nbsp;?</h3>
<p> Lancer un programme, c'est créer un
<em>processus</em>. Tautologisons&nbsp;: <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&nbsp;; 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&nbsp;:
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&nbsp;:
</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 à&nbsp;:</p>
<ul>
<li> ouvrir un nouveau shell dans une nouvelle fenêtre&nbsp;;</li>
<li> attendre la fin de l'un de ces processus.</li>
</ul>
<p>Pour cela, il faut ajouter le signe «&nbsp;&amp;&nbsp;» à la
fin d'une ligne de commande. On peut ainsi taper&nbsp;:</p>
<pre>
<span class="prompt">chaland ~</span> mozilla &amp;
<span class="prompt">chaland ~</span> mozilla &amp;
<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
«&nbsp;&amp;!&nbsp;». Par exemple, si je tape&nbsp;:
</p>
<pre>
<span class="prompt">chaland ~</span> mozilla &amp;!
<span class="prompt">chaland ~</span> mozilla &amp;!
<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&nbsp;: 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&nbsp;?
</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&nbsp;:</p>
<ul>
<li> ou bien je tape&nbsp;:
<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>&nbsp;&mdash; mais tout cela est bien
fastidieux&nbsp;; </li>
<li> ou bien je tape directement&nbsp;:
<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&nbsp;!), je peux taper&nbsp;:</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&nbsp;:</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&nbsp;;
ainsi, si l'on veut que Nano coupe les lignes au bout de 75
caractères, on doit ouvrir Nano en tapant&nbsp;:
</p>
<pre><span class="prompt">chaland ~</span> nano -r 75 hermocrate.txt</pre>
<h4>Options à nom long</h4>
<p>Traditionnellement, et pour 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&nbsp;; ils sont en général
précédés, non d'un, mais de deux tirets. Exemple&nbsp;:</p>
<pre><span class="prompt">chaland ~</span> nano &#45;&#45;fill=75 hermocrate.txt</pre>
<p class="continue">Dans cet exemple, il se trouve que l'option à nom
long <code>&#45;&#45;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&nbsp;: 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&nbsp;:
</p>
<pre>cc -o foo bar.c gee.c buz.c gog.c</pre>
<p class="continue">
(pour les curieux, sachez que cette commande sert à <em>compiler</em> un
programme écrit en langage&nbsp;C, c'est-à-dire à le traduire en langage
machine. Mais avant de vous mettre au langage&nbsp;C, attendez de bien
connaître le shell, il vous apprendra plus facilement et plus
agréablement les bases de la programmation...)
</p>
<p>
Pour éviter les problèmes liés à la frappe de longues lignes de
commandes, on peut utiliser des <em>jokers</em> (<em>wildcards</em> en
anglais). Pourquoi ce nom&nbsp;? Eh bien, dans certains jeux de cartes,
le joker permet de remplacer n'importe quelle carte&nbsp;; 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&nbsp;:
</p>
<ul>
<li> l'étoile (*), qui remplace n'importe quelle séquence de
caractères&nbsp;;</li>
<li> le point d'interrogation, qui remplace n'importe quel
caractère&nbsp;;</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&nbsp;:
</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&nbsp;:</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&nbsp;: 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&nbsp;? Par exemple, comment faire
afficher un point d'interrogation suivi d'une étoile et d'un dollar par
<code>echo</code>&nbsp;?</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&nbsp;:
</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&nbsp;: les <i lang="en">quotations</i> (mot anglais
signifiant <em>citation</em>).
</p>
<p>
Les mécanismes de citation sont les suivants&nbsp;:
</p>
<ul>
<li> le backslash (<code>\</code>), qui protège un caractère de
l'interprétation par le shell&nbsp;;</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&nbsp;;</li>
<li> les guillemets doubles ou <i lang="en">double quotes</i>
(<code>&quot;</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&nbsp;;</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&nbsp;:
</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&nbsp;:
</p>
<pre>
<span class="prompt">chaland ~ $</span> echo '$?*'
$?*</pre>
<h4>Les guillemets doubles ou doubles quotes (<code>&quot;</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&nbsp;:
</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&nbsp;:
</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&nbsp;: <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&nbsp;:
</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. Ou bien vous pouvez revenir à la <a href="index.html">page
centrale sur le shell</a>, d'où vous pourrez vous orienter vers d'autres
parties du cours.</p>
<div class="metainformation">
Basé sur un polycopié de Roberto Di Cosmo, Xavier Leroy et Damien Doligez.
Modifications&nbsp;: Nicolas George, Baptiste Mélès.
Dernière modification le <date value="$Date: 2005-09-07 23:00:04 $" />.
</div>
</body>
</html>