Exécution de tests

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.

La commande test

Tests sur les fichiers

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
$

Tests sur les chaines de caractères

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
$

Tests sur les nombres

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
$

Les opérateurs

Opérateur Signification
! Négation
-a ET
-o OU

Les opérateurs sont exécutés avec une priorité bien précise :

  1. ! (négation)
  2. -a (ET)
  3. -o (OU)

 

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.

Exemples d'utilisation

Utilisation de la commande test avec la structure de controle if.

Principe d'utilisation :

if  commande1 
then
     commande2
     commande3
     ...
else
     commande4
     ...
fi

if  commande1  ; then
     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 [[ ]]

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 ||.

Tests sur les chaines

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
$

Tests logiques

Rappels :

  • Les opérateurs -a et -o sont respectivement remplacés par && et ||
  • Les parenthèses n'ont plus besoin d'être protégées
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
.....