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

512 lines
16 KiB
Text
Raw Normal View History

<?xml version="1.0" encoding="ISO-8859-1"?>
<!DOCTYPE html
PUBLIC "-//ENS/Tuteurs//DTD TML 1//EN"
"tuteurs://DTD/tml.dtd">
<html>
<head>
<title>Commandes</title>
</head>
<body>
<h1>Le shell en ligne de commande</h1>
<h2>Cr<43>er des processus</h2>
<p> Le shell a la facult<6C> de lancer de nombreux programmes, sinon
tous. C'est une des raisons pour lesquelles on peut dire que c'est un
outil extr<74>mement puissant.
</p>
<h3>Qu'est-ce qu'un processus<75>?</h3>
<p> Lancer un programme, c'est cr<63>er un
<em>processus</em>. Tautologisons<6E>: <strong>un processus est une
instance d'ex<65>cution d'un programme</strong>, c'est-<2D>-dire
l'ex<65>cution particuli<6C>re d'un programme universel (<i>i.e</i> qui
n'est pas r<>ductible <20> l'une de ses ex<65>cutions). </p>
<p>Par exemple, si je lance Mozilla, un processus se cr<63>e, du nom de
<code>mozilla</code>. Ensuite, sans fermer ce programme, je lance une
deuxi<EFBFBD>me fois Mozilla<6C>; un nouveau processus se cr<63>e, du nom
de <code>mozilla</code> <20>galement. J'ai donc deux processus
distincts, m<>me s'ils concernent le m<>me programme. Et <20> chaque
fois que je lance un programme, un processus se cr<63>e.
</p>
<h3>G<>n<EFBFBD>alogie des processus</h3>
<p> Dans notre exemple, nous avons deux processus
<code>mozilla</code>. Ils sont ind<6E>pendants l'un de l'autre<72>:
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<6E>pendants l'un de l'autre, tous deux
d<EFBFBD>pendent du processus qui les a lanc<6E>s. Eh oui, <strong>le shell
est un programme comme un autre, donc chacune de ses ex<65>cutions
correspond <20>galement <20> la cr<63>ation d'un processus</strong>. Si
vous lancez trois shells en m<>me temps, par exemple dans trois
terminaux diff<66>rents, vous aurez trois processus <code>shell</code>
distincts. </p>
<p>
Les processus entretiennent entre eux des relations de parent<6E>. 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, <20> chaque fois
que je tape <code>mozilla</code>, mon shell cr<63>e un processus
<code>mozilla</code>. </p>
<h3>Lancer des processus en arri<72>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<6E>:
</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<EFBFBD>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<74>s pratique. Par
exemple, si je veux lancer Mozilla, mais aussi Emacs et d'autres
programmes qui s'ouvrent dans leur propre fen<65>tre, je suis oblig<69>
d'ouvrir <20> chaque fois un nouveau terminal avec un nouveau shell, et
ce uniquement pour y taper une commande, apr<70>s quoi le shell se
retrouve inutilisable jusqu'<27> la fin de chacun de ces
programmes. </p>
<p>Il faudrait donc que l'on puisse <strong>lancer des processus enfants en
arri<EFBFBD>re-plan</strong>, de telle sorte que ces processus se lancent
dans leur propre fen<65>tre et me permettent toutefois de dialoguer avec
le shell sans avoir <20><>:</p>
<ul>
<li> ouvrir un nouveau shell dans une nouvelle fen<65>tre<72>;</li>
<li> attendre la fin de l'un de ces processus.</li>
</ul>
<p>Pour cela, il faut ajouter le signe <20><>&amp;<3B><> <20> la
fin d'une ligne de commande. On peut ainsi taper<65>:</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><3E>manciper un processus enfant</h3>
<p>La vie est d<>j<EFBFBD> plus pratique comme cela. Mais parfois, on
aimerait que le processus enfant survive au processus parent. Car par
d<EFBFBD>faut, <strong>la mort d'un processus parent entra<72>ne celle de
tous ses enfants</strong>. Par exemple, si le shell qui a enfant<6E> les
deux processus <code>mozilla</code> vient <20> d<>c<EFBFBD>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 <20>manciper des
processus enfants, pour que sa propre mort n'entra<72>ne pas les
leurs. Pour cela, il faut utiliser les symboles
<EFBFBD><EFBFBD>&amp;!<21><>. Par exemple, si je tape<70>:
</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'<27>ventuels avertissements, le shell
dispara<EFBFBD>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
<EFBFBD>tait relativement simple<6C>: 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<69>ne, sauf que c'est plus fatigant. Effectivement,
pourquoi se fatiguer <20> taper une suite de caract<63>res quand il
suffit d'appuyer une ou deux fois sur le bouton d'une souris<69>?
</p>
<p>
C'est dans l'usage des arguments et des options que la ligne de commande
commence <20> r<>v<EFBFBD>ler une partie de sa puissance, et de sa nette
sup<EFBFBD>riorit<EFBFBD> sur les interfaces graphiques.
</p>
<h3>Les arguments</h3>
<p>Un argument est une suite de caract<63>res que l'on donne <20> 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'<27>diteur de texte <code>nano</code>, j'ai le choix entre deux
possibilit<EFBFBD>s<EFBFBD>:</p>
<ul>
<li> ou bien je tape<70>:
<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<66>ches pour choisir mes
fichiers, enfin Entr<74>e pour s<>lectionner
<code>hermocrate.txt</code><3E>&mdash; mais tout cela est bien
fastidieux<EFBFBD>; </li>
<li> ou bien je tape directement<6E>:
<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<72>!), je peux taper<65>:</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<65>cute toutes sortes d'information, souvent
plus ou moins p<>riph<70>riques, en g<>n<EFBFBD>ral moins importantes
que les arguments.
</p>
<p>Sous Unix, les options commencent g<>n<EFBFBD>ralement par un
tiret. Certaines options peuvent <20> leur tour prendre des
arguments.</p>
<p>Par exemple, si l'on veut ouvrir un fichier au format MS-DOS, on peut
taper<EFBFBD>:</p>
<pre><span class="prompt">chaland ~</span> nano -D hermocrate.txt</pre>
<h4>Options <20> arguments</h4>
<p>
L'option <code>-r</code> de <code>nano</code> prend un argument<6E>;
ainsi, si l'on veut que Nano coupe les lignes au bout de 75
caract<EFBFBD>res, on doit ouvrir Nano en tapant<6E>:
</p>
<pre><span class="prompt">chaland ~</span> nano -r 75 hermocrate.txt</pre>
<h4>Options <20> nom long</h4>
2005-09-08 01:00:03 +02:00
<p>Traditionnellement, et pour des raisons de concision, la majorit<69>
des options, sous Unix, est compos<6F>e d'un tiret et d'une seule
lettre. Toutefois, pour des raisons pratiques, il peut <20>galement
exister des noms d'option longs<67>; ils sont en g<>n<EFBFBD>ral
pr<EFBFBD>c<EFBFBD>d<EFBFBD>s, non d'un, mais de deux tirets. Exemple<6C>:</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 <20> nom
long <code>&#45;&#45;fill=</code> <20>quivaut <20> l'option <20> nom
court <code>-r</code>. Mais toutes les commandes courtes n'ont pas
syst<EFBFBD>matiquement leur <20>quivalent <20> nom long, et vice versa.</p>
<h2>Jokers et citations</h2>
<h3><a name="raccourcis">Raccourcis pour les noms de fichiers<72>: les
jokers</a></h3>
<p>
Il est souvent ennuyeux d'avoir <20> taper une longue liste de fichiers
pour les donner en arguments <20> une commande, comme<6D>:
</p>
<pre>cc -o foo bar.c gee.c buz.c gog.c</pre>
2005-09-08 01:00:03 +02:00
<p class="continue">
(pour les curieux, sachez que cette commande sert <20> <em>compiler</em> un
programme <20>crit en langage<67>C, c'est-<2D>-dire <20> le traduire en langage
machine. Mais avant de vous mettre au langage<67>C, attendez de bien
2005-09-08 01:00:03 +02:00
conna<EFBFBD>tre le shell, il vous apprendra plus facilement et plus
agr<EFBFBD>ablement les bases de la programmation...)
</p>
<p>
2005-09-08 01:00:03 +02:00
Pour <20>viter les probl<62>mes li<6C>s <20> la frappe de longues lignes de
commandes, on peut utiliser des <em>jokers</em> (<em>wildcards</em> en
anglais). Pourquoi ce nom<6F>? Eh bien, dans certains jeux de cartes,
le joker permet de remplacer n'importe quelle carte<74>; dans le
2005-09-08 01:00:03 +02:00
shell, les jokers permettent de remplacer n'importe quel caract<63>re ou
n'importe quelle s<>quence de caract<63>res.
</p>
<p>
Il existe principalement trois types de jokers<72>:
</p>
<ul>
<li> l'<27>toile (*), qui remplace n'importe quelle s<>quence de
caract<EFBFBD>res<EFBFBD>;</li>
<li> le point d'interrogation, qui remplace n'importe quel
caract<EFBFBD>re<EFBFBD>;</li>
<li> les crochets ([]), qui remplacent n'importe quel caract<63>re d'une
liste d<>termin<69>e.</li>
</ul>
<h4>L'<27>toile : *</h4>
<p>
Une <strong><3E>toile</strong> <code>*</code> dans un nom de fichier est
interpr<EFBFBD>t<EFBFBD>e par le shell comme <20><>n'importe quelle s<>quence de
caract<EFBFBD>res<EFBFBD><EFBFBD> (mais <20>a ignore les fichiers dont le nom commence par un
point). Exemple<6C>:
</p>
<pre>cc -o foo *.c</pre>
<p>
Pour interpr<70>ter l'<27>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<72>e par ordre alphab<61>tique) dans la ligne de commande, et
ex<EFBFBD>cute le r<>sultat, c'est-<2D>-dire par exemple<6C>:
</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<63>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<63>re (<code>.c</code>, <code>.h</code>...).
</p>
<h4>Les crochets : []</h4>
<p>
La forme <code>[abcd]</code> remplace un caract<63>re quelconque parmi
<code>a</code>, <code>b</code>, <code>c</code>, <code>d</code>. Enfin,
<code>[^abcd]</code> remplace un
caract<EFBFBD>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 <20> peu pr<70>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<6F>:
</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 <20> <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'<27>toile par la liste des fichiers pr<70>sents,
et ils seront tous effac<61>s. Si vous tapez <code>rm *~</code>, seuls les
fichiers dont le nom finit par un tilde seront effac<61>s. </li>
</ul>
</div>
<div class="encadre">
<p>
<strong>Interlude<64>:</strong> comment effacer un fichier nomm<6D>
<code>?*</code><3E>? On ne peut pas taper <code>rm<72>?*</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 <20> chaque fichier. On r<>pond
<code>n</code> <20> toutes les questions sauf <code>rm: remove <20>?*</code>.
Autre m<>thode: utiliser les m<>canismes de citation.
</p>
</div>
<h3><a name="quotation">Contourner les jokers<72>: la citation (<i
lang="en">quotation</i>)</a></h3>
<p>
Avec tous ces caract<63>res sp<73>ciaux, comment faire pour passer des
arguments bizarres <20> une commande<64>? Par exemple, comment faire
afficher un point d'interrogation suivi d'une <20>toile et d'un dollar par
<code>echo</code><3E>?</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<70>ter
comme des jokers<72>:
</p>
<pre><span class="prompt">chaland ~</span> echo ?*$
zsh: no matches found: ?*$</pre>
<p> Il faut donc indiquer au shell de ne pas interpr<70>ter ces caract<63>res
comme des jokers. Pour cela, nous allons utiliser des m<>canismes fournis
par le shell<6C>: les <i lang="en">quotations</i> (mot anglais
signifiant <em>citation</em>).
</p>
<p>
Les m<>canismes de citation sont les suivants<74>:
</p>
<ul>
<li> le backslash (<code>\</code>), qui prot<6F>ge un caract<63>re de
l'interpr<70>tation par le shell<6C>;</li>
<li> les apostrophes ou <i lang="en">simple quotes</i>
(<code>'</code>), qui prot<6F>gent une cha<68>ne de caract<63>res de
l'interpr<70>tation par le shell<6C>;</li>
<li> les guillemets doubles ou <i lang="en">double quotes</i>
(<code>&quot;</code>), qui prot<6F>gent <20>galement une cha<68>ne de caract<63>res
de l'interpr<70>tation par le shell, mais avec plus de souplesse que les
pr<EFBFBD>c<EFBFBD>dents<EFBFBD>;</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<70>c<EFBFBD>der un caract<63>re sp<73>cial d'un backslash, et le shell
remplace ces deux caract<63>res par le caract<63>re sp<73>cial seul. <20>videmment, le
backslash est lui-m<>me un caract<63>re sp<73>cial.
</p>
<p>
Exemples<EFBFBD>:
</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<68>ne de caract<63>res entre apostrophes
(simples quotes) <code>'</code>. Tout ce qui se trouve entre deux
apostrophes sera pass<73> tel quel par le shell <20> la
commande. Exemple<6C>:
</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, <20> une exception pr<70>s: les
dollars et les backslashes sont interpr<70>t<EFBFBD>s entre les guillemets.
Exemple<EFBFBD>:
</p>
<pre>
<span class="prompt">chaland ~ $</span> echo "$HOME/*"
/users/87/maths/doligez/*</pre>
<p>
Une technique utile: Quand on juxtapose deux cha<68>nes de caract<63>res
quot<EFBFBD>es, le shell les concat<61>ne, et elles ne forment qu'un argument.
Exemple<EFBFBD>:
</p>
<pre>
<span class="prompt">chaland ~ $</span> echo "'"'"'
'"</pre>
<p>
Quant aux interactions plus compliqu<71>es (backslashes <20> l'int<6E>rieur des
guillemets, guillemets <20> l'int<6E>rieur des apostrophes, etc.), le meilleur moyen
de savoir si <20>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<EFBFBD>re forme de citation<6F>: <code>`<em>commande</em>`</code>. Le
shell ex<65>cute la <em>commande</em> indiqu<71>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<EFBFBD>:
</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<6F>e ci-dessus affiche sur sa
sortie le nom absolu du fichier ex<65>cut<75> par le shell quand on lance la
commande it <em>cmd</em><3E>:
</p>
<pre>
<span class="prompt">chaland ~ $</span> which emacs
/usr/local/bin/emacs</pre>
<p>Vous <20>tes maintenant en mesure de faire ces <a
href="&url.tuteurs;unix/exercices/">exercices</a> pour vous
2005-09-08 01:00:03 +02:00
entra<EFBFBD>ner. Ou bien vous pouvez revenir <20> 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<EFBFBD> sur un polycopi<70> de Roberto Di Cosmo, Xavier Leroy et Damien Doligez.
Modifications<EFBFBD>: Nicolas George, Baptiste M<>l<EFBFBD>s.
Derni<EFBFBD>re modification le <date value="$Date: 2007-07-17 10:03:40 $" />.
</div>
</body>
</html>