PROFDINFO.COM

Votre enseignant d'informatique en ligne

Section 3 - Codes de retour et existence de fichiers

Retour à la page du cours

Nous apprendrons dans cette section comment vérifier si une opération dans notre script s'est bien passée, afin d'éviter de continuer dans le cas d'une erreur. Réciproquement, nous verrons comment retourner des codes d'erreurs dans nos scripts afin que quelqu'un puisse faire la même chose et savoir si nos scripts ont fonctionné ou pas. Finalement nous verrons deux autres conditions utilisables pour vérifier l'existence de fichiers et de répertoires, ce qui est bien pratique lorsque l'on veut les manipuler sans problème.

3.1 - Tester le résultat d'une commande dans un script avec $?

3.2 - L'envers de la médaille: retourner un code d'erreur

3.3 - Vérifier l'existence d'un fichier ou d'un répertoire

3.4 - Un petit exercice

3.1 - Tester le résultat d'une commande dans un script avec $?

On l'a déjà vu, un script n'interrompt pas son exécution lorsqu'il rencontre une erreur -  il affiche simplement les messages d'erreur à l'écran (en fait sur le stderr – standard error) et il tente de continuer son exécution tant bien que mal.

Souvent, si la première opération que fait le script ne fonctionne pas, ça ne sert à rien de tenter de continuer, on arrivera seulement à encore plus d'erreurs.  Parfois, continuer après une erreur peut même causer des problèmes importants (rappelez-vous le script DetruireGroupe appelé sans paramètres...).

Pour éviter cela, il est toujours bon de s'assurer que les parties critiques de notre script fonctionnent correctement et de forcer le script à s'arrêter en cas d'erreur.  Il existe bien des cas où une erreur peut survenir même si le bon nombre de paramètres a été donné. C'est dans ces cas-là qu'on utilisera la variable spéciale $?

Le $? contient le code de retour de la dernière opération effectuée.  Qu'est-ce qu'un code de retour?  C'est un chiffre retourné par tout programme, script ou commande, qui nous indique si tout a fonctionné correctement et qui nous donne parfois quelques précisions en cas d'erreur.  Ce chiffre n'est jamais affiché à l'écran, il est simplement retourné au "parent", c'est à dire à celui qui l'a appelé, qui lui a demandé de s'exécuter.

Dans le cas d'un programme ou d'une commande lancée au prompt, le parent est le shell dans lequel vous êtes lorsque vous faites exécuter le programme.  Le shell (l'interpréteur de commandes) recevra le code de retour mais ne fera rien de spécial avec lui.  Dans le cas d'un programme lancé dans un script, c'est le script qui est le parent et c'est donc lui qui recevra le code d'erreur.  À vous de décider ce que vous en faites.

Par convention, sur Unix, lorsqu'un programme termine "correctement" (c'est à dire sans erreur), il retourne 0 (le nombre zéro).  Sinon, il retourne un autre nombre, presque toujours positif.  Ce nombre peut être différent selon le type d'erreur, mais s'il n'est pas 0, on sait qu'il y a eu un problème et c'est souvent tout ce qu'on veut savoir.

Il est fort utile de placer le contenu de $? dans une variable immédiatement, pour pouvoir y référer plus tard.  N'oubliez pas que $? contient le résultat de la dernière commande exécutée, donc si vous la relisez à un autre moment du script elle ne contiendra peut-être plus ce que vous voulez. En plus, si on en a besoin plus tard dans le script (par exemple pour l'afficher), c'est bon de l'avoir conservé.

Par exemple:

mv file1 $HOME/files
echo "Tentative de déplacement du fichier"
if [ $? –eq 0 ]; then
   echo "Déplacement réussi"
else
   echo "Erreur, le fichier n'est pas déplacé"
fi

Dans cet exemple, le $? utilisé dans le if contiendra le code de retour du echo précédent, pas celui du mv...  Fort probablement, le echo aura fonctionné donc le $? contiendra toujours 0, même si le mv a échoué.  Il est plus prudent de stocker le $? dans une variable immédiatement après la commande, comme ceci:

mv file1 $HOME/files
RESULT=$?
echo "Tentative de déplacement du fichier"
if [ $RESULT –eq 0 ]; then
   echo "Déplacement réussi"
else
   echo "Erreur, le fichier n'est pas déplacé"
fi

Retour à la table des matières de la section

3.2 - L'envers de la médaille: retourner un code d'erreur

Évidemment, si l'on veut pouvoir se fier au code de retour d'un script, il faut prendre l'habitude d'en retourner nous aussi dans les nôtres...  Pour faire cela, rien de plus simple:  utiliser la commande exit.

La commande exit, utilisée seule, termine immédiatement l'exécution du script.  Mais on peut également lui donner un chiffre en paramètre et dans ce cas le script sera arrêté et le chiffre sera retourné comme code de retour.

Par exemple, reprenons notre script de tout à l'heure:

mv file1 $HOME/files
RESULT=$?
echo "Tentative de déplacement du fichier"
if [ $RESULT –eq 0 ]; then
   echo "Déplacement réussi"
   exit 0
else
   echo "Erreur, le fichier n'est pas déplacé"
   exit $RESULT
fi

De cette façon, si ce script est utilisé à l'intérieur d'un autre, l'autre pourra savoir avec un $? si le déplacement a fonctionné ou pas! En effet, si le code de retour du mv est un nombre positif, on sait que le mv n'a pas fonctionné. Dans ce cas, on affiche un message d'erreur correspondant, puis on retourne le code d'erreur du mv.

Voilà en plus un exemple qui montre l'importance de stocker la valeur de $? dans une variable. 

Notez que le exit 0 n'est pas absolument nécessaire, puisqu'un script qui arrive à la dernière ligne termine automatiquement avec le code de retour 0. Toutefois, c'est plus clair de l'indiquer dans le if.

C'est une très bonne habitude d'utiliser exit avec des codes de retour dans le cas où une erreur a eu lieu. Ainsi, si un jour on fait un script qui appelle nos scripts, on pourra savoir si tout a fonctionné.

Retour à la table des matières de la section

3.3 - Vérifier l'existence d'un fichier ou d'un répertoire

En plus des switches de comparaisons que l'on a vues (-eq, -gt, -lt, etc...) il en existe d'autres fort utiles:  -f et -d.  Ces deux switches permettent de vérifier l'existence d'un fichier (f) ou d'un répertoire (d – directory).  Par exemple:

if [ -f $HOME/.environnement ]; then
   source $HOME/.environnement
   echo "Environnement chargé"
else
   echo "Pas de définition d'environnement à charger"
   exit 1
fi

La condition sera vraie si le fichier $HOME/.environnement existe, c'est à dire si un fichier .environnement se trouve dans le répertoire maison de l'usager courant (n'oubliez pas que sur tout système qui se respecte la variable HOME contient le chemin complet vers le répertoire maison de l'usager en cours, quel qu'il soit.)


La même chose peut-être vérifiée pour un répertoire:

if [ -d $HOME/scripts ]; then
   mv $1 $HOME/scripts
   echo "Fichier déplacé dans $HOME/scripts"
else
   echo "Le répertoire $HOME/scripts n'existe pas. Le créer (o/n)?"
   read REPONSE
   if [ "$REPONSE" = "o" ]; then
      mkdir $HOME/scripts
      mv $1 $HOME/scripts
      echo "Répertoire créé et fichier déplacé"
   else
      echo "Fichier non déplacé"
      exit 1
   fi 
fi

Pouvez-vous expliquer le fonctionnement de ce script?

Retour à la table des matières de la section

3.4 - Un petit exercice

Créez un script appelé filer qui réalise les opérations suivantes:

  • Accepte deux paramètres:  une switch et un nom de fichier
  • La switch déterminera l'opération à effectuer sur le fichier: 
    • -d = delete:  le fichier sera simplement effacé
    • -m = move to home:  le fichier sera déplacé vers le répertoire maison de l'usager
    • -c = copy to home:  le fichier sera copié vers le répertoire maison de l'usager.
    • -h = help:  aucune opération effectuée, un message d'aide est affiché à l'écran expliquant les options possibles.
  • Au départ, le script vérifie si le fichier existe.  S'il n'existe pas, il donne un message d'erreur puis termine avec le code de retour 1.
  • Si le fichier existe et que l'on demande un delete, le script efface le fichier et termine avec un code de retour 0.
  • Si le fichier existe et que l'on demande un move ou un copy, il vérifie si un fichier du même nom existe déjà dans le répertoire home de l'usager.  Si oui, ce fichier sera écrasé par l'opération alors le script demande à l'usager si c'est bien ce qu'il veut faire.
    • Si la réponse est oui, l'opération est effectuée et le script termine avec code de retour 0.
    • Si la réponse est non, le script termine avec code de retour 2 (et rien n'est effectué)

Retour à la table des matières de la section