La commande test permet de faire des tests sur des fichiers, des chaines de caractères et des nombres.
Elle renvoie le code retour 0 (vrai) ou 1 (faux) qu'il est possible de consulter en affichant la valeur de $?
Il existe 2 syntaxes pour utiliser la commande test
$ test expression
$ [ expression ]
La paire de crochet signifie la même chose que la commande test.
Les crochets ouvrants et fermants doivent obligatoirement être suivis et précédés d'un espace.
Expression | Code de retour |
---|---|
-b FILE | Vrai si le fichier existe et est du type spécial bloc |
-c FILE | Vrai si le fichier existe et est du type spécial caractère |
-d FILE | Vrai si le fichier existe et est du type répertoire |
-e FILE | Vrai si le fichier existe |
-f FILE | Vrai si le fichier existe et est du type ordinaire |
-G FILE | Vrai si le fichier existe et si l'utilisateur appartient au groupe propriétaire du fichier |
-h FILE | Vrai si le fichier existe et est du type lien symbolique |
-L FILE | Vrai si le fichier existe et est du type lien symbolique (idem -h) |
-O FILE | Vrai si le fichier existe et si l'utilisateur est le propriétaire du fichier |
-r FILE | Vrai si le fichier existe et est accessible en lecture |
-s FILE | Vrai si le fichier existe et n'est pas vide |
-S FILE | Vrai si le fichier existe et est du type socket |
-w FILE | Vrai si le fichier existe et est accessible en écriture |
-x FILE | Vrai si le fichier existe et est exécutable |
FILE1 -ef FILE2 | Vrai si les fichiers ont le même lien physique |
FILE1 -nt FILE2 | Vrai si FILE1 est plus récent que FILE2 |
FILE1 -ot FILE2 | Vrai si FILE1 est plus ancien que FILE2 |
Exemple :
Le fichier /etc/group est un fichier ordinaire
$ test -f /etc/group
$ echo $?
0
$
Le fichier /etc/groupe n'existe pas (test avec l'autre syntaxe)
$ [ -f /etc/groupe ]
$ echo $?
1
$
Le fichier /etc/init.d existe et est un répertoire
$ [ -d /etc/init.d ]
$ echo $?
0
$
Le fichier /etc/group n'est pas un répertoire ou il n'exsite pas
$ test -d /etc/group
$ echo $?
1
$
Le fichier contenu dans la variable file n'est pas un répertoire ou n'existe pas
$ file=/etc/group
$ test -d $file
$ echo $?
1
$
L'utilisateur n'a pas le droit d'écriture sur le fichier /etc/group
$ [ -w /etc/group ]
$ echo $?
1
$
Expression | Code de retour |
---|---|
-n STRING | Vrai si la longueur de la chaine n'est pas égale à 0 |
-z STRING | Vrai si la longueur de la chaine est égale à 0 |
STRING1 = STRING2 | Vrai si les 2 chaines sont égales |
STRING1 != STRING2 | Vrai si les 2 chaines sont différentes |
STRING | Vrai si la chaine n'est pas vide (idem -n) |
Pour les tests sur les chaines de caractères, il est recommandé de mettre le nom des variables entre guillemets.
Exemple :
Avec les variables suivantes :
$ str1="test1"
$ str2="test2"
$ str3="test1"
$
La variable $str1 n'est pas vide
$ [ -n "$str1" ]
$ echo $?
0
$
$ [ "$str1" ]
$ echo $?
0
$ [ -z "$str1" ]
$ echo $?
1
$
La variable $str4 est vide
$ [ -n "$str4" ]
$ echo $?
1
$
$ [ -z "$str4" ]
$ echo $?
0
$
$ [ "$str4" ]
$ echo $?
1
$
$str1 & $str3 sont identiques
$ [ "$str1" = "$str3" ]
$ echo $?
0
$
$ [ "$str1" != "$str3" ]
$ echo $?
1
$
$str1 & $str2 sont différentes
$ [ "$str1" != "$str2" ]
$ echo $?
0
$
$ [ "$str1" = "$str2" ]
$ echo $?
1
$
Expression | Code de retour |
---|---|
INT1 -eq INT2 | Vrai si INT1 est égal à INT2 (=) |
INT1 -ge INT2 | Vrai si INT1 est supérieur ou égal à INT2 (>=) |
INT1 -gt INT2 | Vrai si INT1 est supérieur à INT2 (>) |
INT1 -le INT2 | Vrai si INT1 est inférieur ou égal à INT2 (<=) |
INT1 -lt INT2 | Vrai si INT1 est inférieur à INT2 (<) |
INT1 -ne INT2 | Vrai si INT1 est différent de INT2 (!=) |
Exemple :
Avec les variables suivantes
$ int1=1
$ int2=2
$ int3=3
$ int4=2
$
$int2 & $int4 sont égaux
$ [ $int2 -eq $int4 ]
$ echo $?
0
$int2 est supérieur ou égal à $int4
$ [ $int2 -ge $int4 ]
$ echo $?
0
$int3 est supérieur ou égal à $int1
$ [ $int3 -ge $int1 ]
$ echo $?
0
$int4 n'est pas supérieur ou égal à $int3
$ [ $int4 -ge $int3 ]
$ echo $?
1
$int3 est supérieur à $int2
$ [ $int3 -gt $int2 ]
$ echo $?
0
$int2 n'est pas supérieur à $int3
$ [ $int2 -gt $int3 ]
$ echo $?
1
$int2 est inférieur ou égal à $int3
$ [ $int2 -le $int3 ]
$ echo $?
0
$int2 est inférieur à $int3
$ [ $int2 -lt $int3 ]
$ echo $?
0
$int2 est inférieur ou égal à $int4
$ [ $int2 -le $int4 ]
$ echo $?
0
$int2 est différent de $int3
$ [ $int2 -ne $int3 ]
$ echo $?
0
$int2 n'est pas différent de $int4
$ [ $int2 -ne $int4 ]
$ echo $?
1
$
Opérateur | Signification |
---|---|
! | Négation |
-a | ET |
-o | OU |
Les opérateurs sont exécutés avec une priorité bien précise :
Le fichier /etc/group n'est pas un répertoire
$ [ ! -d /etc/group ]
$ echo $?
0
$
Le fichier monPremierScript.sh existe et est exécutable
$ [ -f monPremierScript.sh -a -x monPremierScript.sh ]
$ echo $?
0
$
Le fichier monPremierScript.sh n'est pas un répertoire mais il est exécutable
$ [ -d monPremierScript.sh -o -x monPremierScript.sh ]
$ echo $?
0
$
Il est possible de modifier la priorité d'exécution des opérateurs en utilisant des paranthèses.
\(........\)
Les parenthèses doivent être protégées par des antislashes afin de ne pas être interprétées par le shell comme étant un regroupement de commandes.
L'utilisateur doit avoir le droit d'écriture sur le fichier fic1 et le fichier fic4 ou fic7 doit exister
$ ls
fic1 fic2 fic3 fic4 fic5 fic6 script.sh
$ [ -w fic1 -a \( -e fic4 -o -e fic7 \) ]
$ echo $?
0
$
Il doit toujours y avoir un espace autour des opérateurs !, -a et -o.
Utilisation de la commande test avec la structure de controle if.
Principe d'utilisation :
if commande1
then
commande2
commande3
...
else
commande4
...
fi
if
commande2
commande3
...
else
commande4
...
fi
La commande1 est exécutée, si son code retour ($?) vaut 0 (vrai) alors les commandes 2 & 3 sont exécutées, sinon c'est la commande4 qui est exécutée (code retour de la commande1 supérieur à 0 - faux).
Exemple :
Dans l'exemple suivant, le script test s'il reçoit bien au minimum 2 arguments.
Dans le cas contraire, le script affiche un message indiquant que le nombre d'arguments est incorrect et se termine en retournant un code erreur 1.
$ nl monTroisiemeScript.sh
1 #! /bin/bash
2 # Ce script doit recevoir en premier argument le nom d'un dossier puis des noms de fichiers pour les suivants
4 # Ce script doit recevoir au minimum 2 arguments
5 # Le premier étant le nom d'un dossier
6 # Les suivants étant les noms des fichiers
7 # On test si il y a 2 arguments au minimum et on retourne le code erreur 1 si c'est faux
8 if [ $# -lt 2 ]
9 then
10 echo "Nombre d'arguments incorrect !!!"
11 exit 1
12 fi
13 # On sauvegarde le premier argument dans la variable rep
14 rep=$1
15 # On décale tous les arguments avec la commande shift
16 shift
17 # Création du répertoire
18 mkdir $rep
19 # On se positionne dans le nouveau répertoire
20 cd $rep
21 # Création des fichiers dans le nouveau répertoire
22 for fichier in $*
23 do
24 touch $fichier
25 done
26 exit 0
$ ./monTroisiemeScript.sh test
Nombre d'arguments incorrect !!!
$ echo $?
1
$
$ ./monTroisiemeScript.sh test3 coucou
$ echo $?
0
$
La commande [[ ]] est une version améliorée de la commande test.
Tous les opérateurs utilisés avec la commandes test restent valables à l'exception des opérateurs logiques -a et -o respectivement remplacés par && et ||.
Contrairement à la commande test, il n'est plus nécessaire d'entourer les variables avec des guillemets.
Les différentes syntaxes utilisables :
$ echo $null
$ test -z "$null"
$ echo $?
0
$ [ -z "$null" ]
$ echo $?
0
$ [[ -z $null ]]
$ echo $?
0
$ [[ -z "$null" ]]
$ echo $?
0
$ [[ $null = "" ]]
$ echo $?
0
$
Les opérateurs suivants ont été ajoutés :
Opérateurs | Code de retour |
---|---|
$chaine = modele | Vrai si $chaine correspond au modèle |
$chaine != modele | Vrai si $chaine ne correspond pas au modèle |
$chaine1 < $chaine2 | Vrai si $chaine1 est lexicographiquement avant $chaine2 |
$chaine1 > $chaine2 | Vrai si $chaine1 est lexicographiquement après $chaine2 |
En utilisant les expressions, il est possible de comparer des chaines à des modèles identiques à celles permettant le remplacement des noms de fichiers.
Caractères spéciaux pour modèles de chaines de caractères | Signification |
---|---|
Caractères spéciaux valables dans tous les shells : | |
* | 0 à n caractères |
? | 1 caractère quelconque |
[abc] | 1 caractère parmis ceux inscrits entre les crochets |
[!abc] | 1 caractère ne faisant pas partie de ceux inscrits entre les crochets |
Caractères spéciaux non valides en Bourne Shell. En bash, il faut activer l'option extglob (shopt -s extglob) |
|
?(expression) | de 0 à 1 fois l'expression |
*(expression) | de 0 à n fois l'expression |
+(expression) | de 1 à n fois l'expression |
@(expression) | 1 fois l'expression |
!(expression) | 0 fois l'expression |
?(expression1 | expression2 | ...) *(expression1 | expression2 | ...) +(expression1 | expression2 | ...) @(expression1 | expression2 |...) !(expression1 | expression2 | ...) |
alternatives |
Exemple :
Le script suivant test si le numéro de téléphone saisi correspond bien au format +33240346523 ou 0240346523
$ nl test_telephone.sh
1 #! /bin/bash
2 echo -e "Saisir un numéro de téléphone : \c"
3 read telephone
4 # Test si le téléphone saisi est de la forme
5 # +33240346523 ou 0240346523
6 if [[ $telephone = @(+33)@([1-9])@([0-9])@([0-9])@([0-9])@([0-9])@([0-9])@([0-9])@([0-9])@([0-9]) ||
7 $telephone = @(0)@([0-9])@([0-9])@([0-9])@([0-9])@([0-9])@([0-9])@([0-9])@([0-9])@([0-9]) ]]
8 then
9 echo "Le numéro est correct"
10 exit 0
11 else
12 echo "Le numéro est incorrect"
13 exit 1
14 fi
$ ./test_telephone.sh
Saisir un numéro de téléphone : 0240020202
Le numéro est correct
$ ./test_telephone.sh
Saisir un numéro de téléphone : +33256985478
Le numéro est correct
$ ./test_telephone.sh
Saisir un numéro de téléphone : 2356958457
Le numéro est incorrect
$ ./test_telephone.sh
Saisir un numéro de téléphone : +33025146987
Le numéro est incorrect
$ ./test_telephone.sh
Saisir un numéro de téléphone : g52365
Le numéro est incorrect
$
Rappels :
Commande test ( [ ] ) | Commande [[ ]] | Signification |
---|---|---|
\(.....\) | (.....) | Regroupement d'expressions |
! | ! | Négation |
-a | && | ET logique |
-o | || | OU logique |
Exemple avec la commande test :
if [ -w $fic1 -a \( -e $rep1 -o -e $rep2 \) ]
then
.....
Exemple avec la commande [[ ]] :
if [[ -w $fic1 && ( -e $rep1 || -e $rep2 ) ]]
then
.....