Un test est une opération dont le but est d'évaluer la valeur d'une expression. Cette expression peut être simplement l'existence de quelque chose (par exemple, d'un fichier, ou bien d'une variable), ou ce peut être une proposition.
Concrètement, cela veut dire qu'un programme n'est pas limité à la possibilité de donner des ordres : il peut aussi poser des questions, et agir comme vous le décidez en fonction des réponses apportées aux questions.
Posons par exemple le principe suivant : « Si Dieu n'existe pas, alors tout est permis. » Nous allons ensuite tester si Dieu existe, et s'il n'existe pas, nous saurons que tout est permis. Autre exemple : posons que « si le train passe sous le tunnel avant que j'aie compté jusqu'à dix, alors Manek est vivant. » Je vais donc tester si le train passe sous le tunnel avant que j'aie compté jusqu'à dix, et si c'est le cas, alors c'est que Manek est vivant. C'est aussi simple que cela.
Le shell propose deux principales façons de réaliser un test ; ces deux méthodes sont équivalentes :
test expression
[ expression ]
Les deux commandes suivantes reviennent donc au même :
clipper ~ $ test -f foo || echo "Le fichier foo n'existe pas." Le fichier foo n'existe pas. clipper ~ $ [ -f foo ] || echo "Le fichier foo n'existe pas." Le fichier foo n'existe pas.
Un test renvoie un code de retour. Un code de retour
est un nombre (0 ou autre), qui correspond à une réponse de
type « vrai » ou « faux ». C'est ce code de
retour qui permet la manipulation des tests dans des structures de
contrôle comme if
, etc.
Le code de retour 0 correspond à la réponse « vrai ». Pour répondre « faux », le programme répond... autre chose (ce peut être 1, 2, -1 ou autre).
Par exemple, un conducteur de voiture utilise le programme suivant :
while [[ "$couleur_du_feu" != "vert" ]] do attendre done démarrer
!
»L'opérateur logique « non » inverse le code de retour d'une commande, c'est-à-dire renvoie vrai si elle renvoie faux, et vice versa.
On utilise cet opérateur en précédant une condition d'un point d'exclamation (« ! »).
Pour illustrer l'usage de cet opérateur, voici quatre cas de figure différents :
# Premier cas [ -f foo ] && echo "Le fichier foo existe."
Dans l'exemple précédent, le shell teste si le
fichier foo
existe. Comme il n'existe pas, le code de
retour de ce test est faux (un nombre différent de 0). Or, l'opérateur
« && » n'exécute ce qui suit que si le code de retour est vrai
(i.e. 0) car si a
est faux
alors a&&b
sera aussi nécessairement faux. Comme
ce n'est pas le cas, les commandes ne sont pas exécutées.
# Deuxième cas [ -f foo ] || echo "Le fichier foo n'existe pas." Le fichier foo n'existe pas.
Dans cet exemple, l'opérateur n'est plus
« && » mais « || ». Les commandes ne s'exécutent que si le
code de retour vaut faux (i.e. différent de 0); comme c'est le cas,
elles sont exécutées. En effet si a
est vrai
alors a||b
sera aussi nécessairement vrai, ce n'est pas la
peine de l'exécuter.
# Troisième cas [ ! -f foo ] && echo "Le fichier foo n'existe pas." Le fichier foo n'existe pas.
Ici, l'opérateur est de nouveau « && » ;
mais contrairement aux deux exemples précédents, le test n'est
plus [ -f foo ]
mais [ ! -f foo ]
. Par
conséquent, le code de retour est vrai (i.e. 0), et les commandes sont
exécutées.
# Quatrième cas [ ! -f foo ] || echo "Le fichier foo existe."
Voici la dernière combinaison possible. Le code de retour est vrai (i.e 0), mais il fallait faux (e.g. 1) pour que les commandes soient exécutées.
Ces quatre exemples correspondent aux énoncés suivants :
foo
existe, alors il faut
écrire : « Le fichier foo existe. ».foo
existe, alors il
faut écrire : « Le fichier foo n'existe pas. ».foo
n'existe pas, alors il
faut écrire : « Le fichier foo n'existe pas. ».foo
n'existe pas,
alors il faut écrire : « Le fichier foo existe. ».if
Dans un script, outre la formulation précédente, on pourra écrire :
# Premier cas if [ -f foo ] then echo "Le fichier foo existe." else continue fi # Deuxième cas if [ -f foo ] then continue else echo "Le fichier foo n'existe pas." fi # Troisième cas if [ ! -f foo ] then echo "Le fichier foo n'existe pas." else continue fi # Quatrième cas if [ ! -f foo ] then continue else echo "Le fichier foo existe." fi
-a
»L'opérateur « et » renvoie 0 (vrai) si et seulement si les différentes conditions sont toutes réalisées ; si au moins l'une d'entre elles ne l'est pas, le code de retour est 1 (faux). On note cet opérateur en insérant « -a » entre les différentes conditions. Exemples :
touch foo # donc foo existe rm bar # donc bar n'existe pas # [ -f foo ] = vrai si le fichier foo existe # [ ! -f bar ] = vrai si bar n'existe pas # à n'exécuter que si foo existe ET que bar n'existe pas. [ -f foo -a ! -f bar ] && mv foo bar
Autres formulations possibles :
test -f foo -a ! -f bar [ -f foo ] -a [ ! -f bar ] [[ -f foo && ! -f bar ]]
Si vous débutez, vous n'êtes pas tenu de retenir par cœur toutes les combinaisons possibles. Sachez simplement les reconnaître si vous les lisez quelque part ; et pour vos propres scripts, vous il vous suffit de savoir bien manipuler la syntaxe qui vous paraît la plus lisible.
-o
»Pour réaliser la condition de l'opérateur « ou », il suffit qu'une seule des conditions qu'il rassemble soit vraie :
Exemple :
if [[ "$fichier" == "fichier_interdit" -o ! -f "$fichier" ]] then echo "Je ne veux pas lire $fichier ou bien il n'existe pas." fi
$fichier
vaut
"fichier_interdit"
, il n'est pas lu ;$fichier
n'existe pas, il n'est pas lu ;$fichier
vaut
"fichier_interdit"
et qu'en plus il n'existe pas,
il n'est pas lu ;$fichier
ne vaut pas
"fichier_interdit"
et qu'il existe bien, il est
lu.Le shell permet d'opérer des calculs arithmétiques, même s'il est moins puissant que d'autres langages (Perl, Scheme, C, etc.) pour cela.
Les opérateurs sont les suivants :
-eq
(equal) : « égal à » (signe
« = ») ;-ne
(not equal) : « différent
de » (signe « ≠ ») ;-gt
(greater than) : « strictement
supérieur à » (signe « > ») ;-lt
(lesser than) : « strictement
inférieur à » (signe « < ») ;-ge
(greater or equal) : « supérieur
ou égal à » (signe « ≥ ») ;-le
(lesser or equal) : « inférieur
ou égal à » (signe « ≤ ») ;On utilise ces opérateurs entre deux nombres ou variables numériques. Par exemple :
#!/bin/sh if test 2 -lt 3 then echo "C'est normal." fi if test 2 -gt 3 then echo "C'est absurde." fi petit=2 grand=3 if test $petit -ne 3 then echo "C'est normal." fi if test 2 -eq $grand then echo "C'est absurde." fi
Si vous exécutez ce programme, vous obtenez :
C'est normal. C'est normal.
Une grande partie de la puissance du shell se déploie dans sa faculté de manipuler des fichiers.
Les principaux opérateurs disponibles sont :
-e
(exists) : vérifie l'existence d'un
fichier ;-f
(file) : vérifie l'existence d'un
fichier, et le fait qu'il s'agisse bien d'un fichier au sens
strict ;-d
(directory) : vérifie l'existence d'un
répertoire ;-L
(link) : vérifie si le fichier est un
lien symbolique ;-s
(size) : vérifie qu'un fichier n'est
pas vide ;-r
(readable) : vérifie si un fichier peut
être lu ;-w
(writable) : vérifie si un fichier peut
être écrit ou modifié ;-x
(writable) : vérifie si un fichier peut
être exécuté ;-nt
(newer than) : vérifie si un fichier
est plus récent qu'un autre ;-ot
(older than) : vérifie si un fichier
est plus ancien qu'un autre.Exemple :
#!/bin/sh if test -e ~/.emacs then echo "~/.emacs existe." else echo "~/.emacs n'existe pas." fi if test -d ~/.emacs then echo "~/.emacs est un répertoire." else echo "~/.emacs n'est pas un répertoire." fi if test -f ~/.emacs then echo "~/.emacs est un fichier." else echo "~/.emacs n'est pas un fichier." fi if test ~/.vimrc -nt ~/.emacs then "~/.vimrc est plus récent que ~/.emacs." fi