1. Les opérateurs &&
et || en shell.
Dans ce paragraphe, on appelle "liste de commandes" un ensemble de commandes situées
sur une même ligne et séparées par des ; (exécution séquentielle)
ou par des | (branchement).
l'opérateur && est un séparateur
de commandes provoquant l'exécution de la liste de commandes liste_commandes2
si la liste de commandes liste_commandes1 renvoie un code
de retour ayant la valeur 0 (qui équivaut à
VRAI en shell).
- Dans la commande :
l'opérateur || est un séparateur de commandes
provoquant l'exécution de la liste de commandes liste_commandes2
si la liste de commandes liste_commandes1 renvoie un code
de retour ayant une valeur différente de 0 (qui
équivaut à FAUX en shell).
Remarque :
Les commandes UNIX retournent un code nul lorsque tout s'est bien passé, et des valeurs
non nulles dans les différents cas d'erreurs. De façon similaire, dans un programme C,
le code de retour est égal à 0 lorsque tout s'est bien passé, et à des valeurs
non nulles dans les différents cas d'erreurs. En shell, la convention
concernant les valeurs VRAI et FAUX est l'inverse de celle du
langage C, c'est-à-dire que VRAI correspond à 0, alors que
FAUX correspond à n'importe quelle valeur non nulle.
2. La commande exit.
Caractéristiques :
- exit signifie "sortie".
- Cette commande permet de sortir d'un shell, en précisant ou non
la valeur du code de retour.
- Il s'agit d'une commande interne, qui peut donc
fortement varier d'un shell à l'autre.
Syntaxe :
Description :
Exemple :
Si la commande :
est tapée dans la fenêtre "racine", sans qu'aucun
shell fils n'ait été lancé, cela provoque une déconnexion.
Codes de retour :
- Si l'argument code_retour existe : la valeur (nécessairement
entière) de code_retour.
- Sinon : le code de retour de la dernière commande précédemment
exécutée.
Remarques :
- La commande exit a un rôle analogue à la fonction exit
du langage C, mais il s'agit toutefois de deux objets bien distincts (on rappelle que le manuel
électronique concernant ces deux objets se consulte en tapant soit
man exit pour la commande exit, soit man -s2 exit
pour la fonction exit).
- Il existe une autre différence entre ces deux objets : alors
que la fonction exit peut retourner n'importe quelle valeur entière, y compris des
valeurs négatives, la commande exit n'accepte comme argument
qu'un code de retour entier positif ou nul.
3. La commande test.
Caractéristiques :
- test a une signification explicite !
- Cette commande permet d'effectuer des tests de comparaison, en renvoyant
le code de retour 0 lorsque le résultat est vrai, et une autre
valeur sinon. Cette commande
est surtout utile pour les structures de contrôle, comme la structure
de contrôle de condition (cf. le paragraphe 4).
Elle ne fournit pas de résultat sur sa sortie standard. Le seul résultat
qu'elle fournit est un code de retour.
Syntaxes et description :
- test comparaisonou[
comparaison ]
(il faut vraiment taper les crochets et respecter les espaces, dans
ce dernier cas)
La comparaison comparaison peut être la combinaison
booléenne de plusieurs comparaisons élémentaires :
- comparaison1 -a comparaison2 pour le ET
logique.
- comparaison1 -o comparaison2 pour le OU
logique.
- ! comparaison3 pour le NON logique.
Il faut bien prendre garde à ne pas confondre -a avec &&,
ni -o avec ||
Des parenthèses précédées de caractères
\ (pour protéger les parenthèses, qui sont
des métacaractères du shell) peuvent être nécessaires
en cas de combinaisons un peu plus compliquées, pour préciser
les priorités, comme dans l'exemple suivant :
! \( comparaison1 -o comparaison2 \)
Chaque comparaison élémentaire doit être écrite
avec la syntaxe suivante :
où expr1 et expr2 désignent des "expressions"
du shell courant (cf. le paragraphe 5).
Le comparateur comparateur ne s'écrit pas comme
en C :
- Si les valeurs de expr1 et expr2 sont des chaînes
de caractères constituées de chiffres :
- -eq désigne l'égalité (abréviation de equal).
- -ne désigne la non égalité (abréviation de not equal).
- -gt signifie "strictement supérieur" (abréviation de greater than).
- -ge signifie "supérieur ou égal" (abréviation de greater or equal).
- -lt signifie "strictement inférieur" (abréviation de less than).
- -le signifie "inférieur ou égal" (abréviation de less or equal).
-
Si les valeurs de expr1 et expr2 sont des chaînes
de caractères quelconques :
- = désigne l'égalité.
- != désigne la non égalité.
- Il faut bien prendre garde à ne pas confondre les comparateurs =
et -eq. Alors que test 2 = 02 retourne FAUX,
que test 2 -eq 02 retourne VRAI
et que test baba = bobo retourne FAUX, ce qui semble
tout à fait cohérent, on sera surpris de constater que test baba -eq bobo
retourne VRAI ! Il ne faut donc pas utiliser le comparateur -eq
pour comparer des chaînes de caractères.
- Pour tester si la variable chaine a comme valeur la
chaîne vide, on ne peut pas écrire test $chaine
= "" car, si cette chaîne était vraiment
vide, après évaluation des métacaractères,
cette commande serait évaluée sous la forme test =,
écriture qui est incorrecte. Cela justifie
l'introduction d'une deuxième syntaxe pour la commande test :
Dans cette écriture, la commande test teste si la variable
chaine a comme valeur la chaîne vide. Si ce n'est pas le cas,
la commande test retourne 0
(c'est-à-dire VRAI).
- test -f|-d|-r|-w|-x nom [...]
Dans cette écriture, la commande test vérifie si
nom est le nom d'un fichier (option -f) ou d'un
répertoire (option -d), et si nom
est accessible en lecture (option -r), en écriture
(option -w) ou est exécutable par l'utilisateur
(option -x).
Exemples :
- test $1 -gt 0 -a $# -eq 2
Cette commande teste si le premier paramètre positionnel a une
valeur entière strictement supérieure à 0,
et si le nombre de paramètres positionnels du shell courant ayant reçu
une valeur est égal à 2
- test -d /users/linfg/linfg0/TD
Cette commande teste si /users/linfg/linfg0/TD est le nom d'un répertoire.
Cette commande teste si nom est le nom d'un fichier accessible
en lecture. Elle est équivalente à :
test -f nom && test -r nom
Codes de retour :
- comparaison évaluée à VRAI
: 0
- comparaison évaluée à FAUX
: 1
- Opération interrompue pour cause d'erreur : > 1
4. La structure de contrôle de condition
en shell.
Dans un script, il est possible de structurer les commandes en effectuant
des appels conditionnels.
Syntaxe :
Remarques :
-
Il est recommandé de respecter l'indentation du modèle ci-dessus, bien que ce modèle ne soit pas obligatoire.
-
Les conditions condition1 et condition2 doivent être
des commandes. La commande la plus souvent utilisée est la commande
test. C'est la valeur du code de retour de cette commande
qui est utilisée comme booléen (avec la convention inverse de celle du langage C).
Exemple :
contenu.sh
|
if [ $# -eq 1 ]
then
echo
"Le répertoire $1 a le contenu suivant : `ls $1`"
else
echo
'Mauvais nombre de paramètres'
fi |
Ce script affiche le contenu du répertoire passé en paramètre.
Si le nombre de paramètres est différent de 1, alors un message est affiché.
5. Les variables d'un shell.
Tout shell permet de gérer des variables.
Le nom d'une variable peut comporter des lettres, des chiffres et le caractère
_ mais le premier caractère ne peut pas être
un chiffre. La valeur d'une variable s'obtient en faisant précéder
le nom de la variable du caractère $. Une variable d'un shell
ne peut avoir comme valeur qu'une chaîne de caractères.
Avec le shell de Bourne, l'affectation d'une valeur à une variable s'effectue
soit à l'aide de la commande read, soit en utilisant la syntaxe suivante :
où expression est une "expression" du shell ayant comme valeur
une chaîne de caractères.
Attention :
- Il ne doit pas y avoir d'espace ni avant ni après le caractère
=
- La syntaxe de l'affectation d'une valeur à une variable dépend beaucoup du shell utilisé.
En particulier, en "C shell", cette syntaxe est très différente de celle qui vient d'être
décrite.
En shell, "l'expression" la plus générale est obtenue par la "concaténation" d'une
ou de plusieurs expressions, qui peuvent être :
- Une chaîne de caractères (exemple : module4).
- La valeur d'un paramètre positionnel (exemple : $2).
- La valeur d'une variable (exemple : $var).
- La capture de la sortie standard d'une commande (exemple : `pwd`).
La concaténation d'expressions s'écrit en juxtaposant ces expressions
et en utilisant, si besoin est, les délimiteurs "
et ', sachant que cela a une influence sur l'interprétation des métacaractères
du shell.
Exemples :
Si le répertoire courant est la racine /, cette séquence produit
l'affichage de 1/
Cette séquence produit l'affichage d'un message d'erreur dû à la présence d'un
caractère espace situé entre les deux expressions $a et `pwd`.
Pour rendre cette séquence correcte, il faut rajouter des délimiteurs " :
Si le répertoire courant est la racine /, cette séquence produit bien
l'affichage de 1 / car les délimiteurs " permettent
l'interprétation des métacaractères $ et `.
En revanche, si on utilise des délimiteurs ', c'est-à-dire pour :
alors l'affichage obtenu est $a `pwd` car aucun métacaractère n'a été interprété.
Remarques :
- Il existe, dans tout shell, un certain nombre de variables prédéfinies.
À la connexion sur marine, la variable prédéfinie path
du shell par défaut (qui n'est pas un shell de Bourne) a comme valeur une liste
de répertoires. Lors de la première séance de travaux pratiques, on avait concaténé
à cette valeur le répertoire courant . (dans la syntaxe du "C shell",
qui est très différente de celle du shell de Bourne).
- Il ne faut pas confondre les variables d'un shell avec ses paramètres
positionnels. Pour modifier la valeur d'un paramètre positionnel,
il faut utiliser la commande set (cf. le prochain paragraphe).
6. La commande set.
Caractéristiques :
- set signifie "placer".
- Cette commande permet d'affecter des valeurs
aux paramètres positionnels $1, $2,
$3, ..., $9 du shell courant. Appelée
sans paramètre, elle permet aussi d'afficher les valeurs de toutes
les variables du shell courant :
- Les variables prédéfinies.
- Les variables définies par l'utilisateur.
- Elle peut apparaître en début de
branchement.
- Il s'agit d'une commande interne, qui peut donc
fortement varier d'un shell à l'autre.
Syntaxe :
Description :
cf. la description de la commande set, en tapant
: man set
Exemples :
- set alpha beta
Cette commande affecte la valeur alpha au paramètre
positionnel $1, et la valeur beta au paramètre
positionnel $2
- x=1
set
produira un affichage du type suivant :
DISPLAY=141.115.12.137:0
...
HOME=/users/linfg/linfg0
...
x=1
Dans cet affichage, la dernière ligne concerne une variable définie
par l'utilisateur, alors que toutes les lignes précédentes
concernent les variables prédéfinies du shell courant.
Codes de retour :
cf. la description de la commande set, en tapant
: man set
Remarque :
La commande set met automatiquement à jour les paramètres
$# et $*
7. La commande expr.
Caractéristiques :
- expr vient de "expression".
- Cette commande permet d'effectuer des opérations arithmétiques
et logiques, ainsi que des opérations sur les chaînes de caractères
plus sophistiquées que la simple concaténation,
et renvoie le résultat de ces opérations sur la sortie standard.
- Elle peut apparaître en début de
branchement.
Syntaxe :
expr argument1 opérateur1 argument2 [opérateur2
argument3 ...]
où les arguments argument1, argument2,
argument3, ... sont des expressions du shell courant, et où les opérateurs opérateur1,
opérateur2, ... appartiennent à la liste
non exhaustive suivante :
- + (addition), - (soustraction), *
(multiplication), / (quotient de la division entière),
% (reste de la division entière), si argument1
et argument2 ont comme valeurs des chaînes de caractères
constituées uniquement de chiffres (et donc interprétables en tant qu'entiers).
- = (égalité), != (différence),
>, >=, <, <=
(comparaisons), si argument1 et argument2
ont comme valeurs des chaînes de caractères quelconques (attention : pour ces opérations,
la valeur VRAI est codée par 1 et la valeur FAUX
par 0, comme en C).
- : (extraction de sous-chaînes de caractères).
Avec cet opérateur, l'argument argument1 peut avoir comme valeur
une chaîne de caractères quelconque, mais l'argument argument2 doit
être une expression régulière (cf. le paragraphe 7
de la séance 11 de travaux dirigés).
On peut spécifier l'ensemble des caractères devant être retirés de la
chaîne argument1 par des caractères et des
métacaractères des expressions régulières,
et on doit indiquer la séquence de caractères à extraire de argument1
grâce à l'expression régulière \(.*\) (dans le cas où la correspondance est impossible, le résultat
de l'opération est la chaîne vide).
Description :
Exemples :
- a=2
b=3
a=`expr $b % $a`
echo $a
produit l'affichage de 1
- chaine="caractères"
sschaine=`expr $chaine : '\(.*\)t'`
echo $sschaine
produit l'affichage suivant :
carac
On aurait pu écrire l'expression régulière
sous d'autres formes, comme par exemple :
'\(.*\)t.*'
'\(.*\)tères'
Codes de retour :
- Résultat de l'opération non nul : 0
- Résultat de l'opération nul : 1
- Syntaxe incorrecte : 2
- Opération interrompue pour cause d'erreur : > 2
Remarques :
-
L'utilisation des cinq opérateurs *, >,
>=, < et <=,
parmi tous ceux qui ont été décrits ci-dessus, nécessite une
vigilance particulière, car *, > et
<, étant des métacaractères du shell, doivent
être protégés. Pour ce faire, on peut soit les faire précéder d'un caractère
\, soit les entourer de délimiteurs " ou '.
- Dans le cas où la commande expr est lancée
avec plusieurs opérateurs, il faut être vigilant, car l'ordre
des opérations ne se fait ni de gauche à droite, ni de droite
à gauche, mais suivant un ordre prédéfini de priorité
des opérateurs.
8. Exercice 1.
1) À l'aide d'une seule ligne de commande, afficher le message OK
si un fichier est un "binaire exécutable".
Remarque :
Lorsqu'on passe en paramètre à la commande file le nom d'un fichier
binaire exécutable, on obtient l'affichage d'une ligne comportant la chaîne de caractères
executable
2) Même question, en écrivant un script mettant en oeuvre
une structure de contrôle de condition.
9. La commande read.
Caractéristiques :
- read signifie "lire".
- Cette commande permet d'affecter des valeurs à des variables
à partir de l'entrée standard. Elle est souvent utilisée à l'intérieur
d'une boucle while. Elle varie beaucoup d'un
shell à l'autre.
- Elle peut apparaître en fin de branchement.
- Il s'agit d'une commande interne, qui peut donc
fortement varier d'un shell à l'autre.
Syntaxe :
Description :
Exemples :
- L'exemple suivant montre que si le nombre de mots (séparés
par des espaces ou des tabulations) est supérieur au nombre d'arguments
de la commande read, alors la variable correspondant au
dernier argument reçoit toute la fin de la ligne :
$ read a b
c'est un exemple
$ echo $a
c'est
$ echo $b
un exemple
$ |
- cat fichier | while read ligne
do
- ...
done
Une séquence de ce type permet de "passer en revue"
toutes les lignes du fichier fichier, de la première
ligne à la dernière ligne.
Codes de retour :
- Pas d'erreur : 0
- Opération interrompue pour cause d'erreur : > 0
Remarque :
Les caractères tapés sur l'entrée standard ne peuvent
pas contenir de caractère retour-chariot, car le premier retour-chariot tapé
a pour effet de renvoyer le prompt.
10. La commande ps.
Caractéristiques :
- ps vient de "process status"
("situation des processus").
- Cette commande permet d'afficher la liste des "processus" en cours d'activité.
Lancée sans option, elle n'affiche que les processus actifs de l'utilisateur
associés à la fenêtre d'où la commande est lancée.
- Elle peut apparaître en début de
branchement.
Syntaxe :
ps [-aAcdefjlLPy] [-g nom] [-n nom] [[-o format] ...] [-p nom] [-s
nom] [-t terminaux] [-u utilisateurs] [-U nom] [-G nom]
Les processus sont affichés, à raison d'un par ligne, suivant un format variable.
Le format par défaut comprend les quatre champs suivants :
- PID : numéro d'identification du processus.
- TTY : terminal associé au processus.
- TIME : temps d'exécution cumulé du processus.
- CMD : nom de la commande associée au processus.
Description :
- -e : affichage des informations sur tous les processus.
- -f : affichage de la description complète des processus, comportant
quatre champs de plus que l'affichage par défaut, et en particulier le nom du propriétaire
du processus (champ UID) et l'heure de lancement du processus
(champ STIME).
- -u utilisateurs : affichage des informations sur tous les processus dont
le propriétaire est contenu dans la liste utilisateurs.
- Autres options : cf. la description de la commande ps,
en tapant : man ps
Exemples :
-
ps -u "crouzil durou"
Cette commande affiche tous les processus en cours d'exécution
sur marine, associés
à un terminal quelconque, dont le propriétaire est crouzil ou durou
(quatre champs affichés par processus).
Codes de retour :
- Pas d'erreur : 0
- Opération interrompue pour cause d'erreur : > 0
11. La commande kill.
Caractéristiques :
- kill signifie "tuer".
- Cette commande permet d'envoyer un signal à un ou à plusieurs
processus dont on connaît les identificateurs.
- Il s'agit d'une commande interne, qui peut donc
fortement varier d'un shell à l'autre.
Syntaxes :
- kill [-signal] identificateur_processus [...]
- kill -l
Description :
- -signal : envoi du signal signal au processus.
- -l : affichage de la liste des signaux qui peuvent
être envoyés à un processus.
Exemple :
La commande kill -9 1345 envoie le signal 9
au processus d'identificateur 1345
Le signal 9, qui permet de "tuer" un
processus, est le plus souvent utilisé. Le signal envoyé
par défaut est 15
Codes de retour :
- Pas d'erreur : 0
- Opération interrompue pour cause d'erreur : > 0
12. Exercice 2.
Écrire un script permettant de compter les fichiers du répertoire
courant (les sous-répertoires du répertoire courant ne doivent donc pas être comptés)
correspondant à l'une des quatre catégories suivantes :
- Fichiers dont le nom se termine par .c
- Fichiers dont le nom se termine par .h
- Fichiers dont le nom commence par .
- Autres fichiers.
Ces pages ont été réalisées
par A. Crouzil, J.D. Durou et Ph. Joly.
Pour tout commentaire, envoyer un mail à
crouzil@irit.fr, à durou@irit.fr ou à Philippe.Joly@irit.fr.