IdentifiantMot de passe
Loading...
Mot de passe oublié ?Je m'inscris ! (gratuit)

Introduction à la programmation en Bash


précédentsommairesuivant

VII. Code de retour

Un code de retour (exit status) est fourni par le shell après exécution d'une commande. Le code de retour est un entier positif ou nul, compris entre 0 et 255, indiquant si l'exécution de la commande s'est bien déroulée ou s'il y a eu un problème quelconque.
Par convention, un code de retour égal à 0 signifie que la commande s'est exécutée correctement. Un code différent de 0 signifie une erreur syntaxique ou d'exécution.

L’évaluation du code de retour est essentielle à l’exécution de structures de contrôle du shell telles que if et while.

VII-1. Paramètre spécial ?

Le paramètre spécial ? (à ne pas confondre avec le caractère générique ?) contient le code de retour de la dernière commande exécutée de manière séquentielle (exécution synchrone).

 
Sélectionnez
$ pwd
/home/sanchis
$ echo $?
0                              => la commande pwd s'est exécutée correctement
$ ls -l vi
ls: vi: Aucun fichier ou répertoire de ce type
$ echo $?
2                              => une erreur s’est produite !
$

Exercice :
En utilisant la commande unix ls et le mécanisme de redirection, écrire un programme shell dansbin prenant un nom de commande en argument et qui affiche 0 si cette commande est présente dans /bin, une valeur différente de 0 sinon.

 
Sélectionnez
$ dansbin     ls
0
$ dansbin    who
2
$

Chaque commande positionne « à sa manière » les codes de retour différents de 0. Ainsi, un code de retour égal à 1 positionné par la commande unix ls n'a pas la même signification qu'un code de retour à 1 positionné par la commande unix grep. Les valeurs et significations du code de retour d’une commande unix ou du shell sont documentées dans les pages correspondantes du manuel (ex : man grep).

Lorsque une commande est exécutée en arrière-plan (exécution asynchrone), son code de retour n'est pas mémorisé dans le paramètre spécial ?.

 
Sélectionnez
$ pwd			  => mise à zéro du paramètre spécial ?
/home/sanchis
$ echo $?
0
$ ls -l vi &              => commande exécutée en arrière-plan
[1] 19331
$ ls: vi: Aucun fichier ou répertoire de ce type
[1]+ Exit 2               ls --color=tty -l vi
$ echo $?
0
$

On remarque que la commande s'est terminée avec la valeur 2 (Exit 2) mais que ce code de retour n'a pas été enregistré dans le paramètre ?. La commande interne deux-points (:) sans argument retourne toujours un code de retour égal à 0.

 
Sélectionnez
$:                         => commande deux-points
$ echo $?
0
$

Il en est de même avec la commande interne echo : elle retourne toujours un code de retour égal à 0, sauf cas particuliers.

 
Sélectionnez
$ 1>&- echo coucou
-bash: echo: write error: Mauvais descripteur de fichier
$ echo $?
1
$

Enfin, certaines commandes utilisent plusieurs valeurs pour indiquer des significations différentes, comme la commande unix grep.

Commande unix grep :
Cette commande affiche sur sa sortie standard l'ensemble des lignes contenant une chaîne de caractères spécifiée en argument, lignes appartenant à un ou plusieurs fichiers texte (ou par défaut, son entrée standard).

La syntaxe de cette commande est : grep [ option(s) ] chaîne_cherchée [ fich_texte1 ... ]

Soit le fichier pass contenant les cinq lignes suivantes :

 
Sélectionnez
        root:x:0:0:root:/root:/bin/bash
        daemon:x:1:1:daemon:/usr/sbin:/bin/sh
        bertrand:x:101:100::/home/bertrand:/bin/bash
        albert:x:102:100::/home/albert:/bin/bash
        sanchis:x:103:100::/home/sanchis:/bin/bash

La commande ci-dessous affiche toutes les lignes du fichier pass contenant la chaîne sanchis.

 
Sélectionnez
$ grep sanchis pass
sanchis:x:103:100::/home/sanchis:/bin/bash
$

grep recherche une chaîne de caractères et non un mot.

 
Sélectionnez
$ grep bert pass
bertrand:x:101:100::/home/bertrand:/bin/bash
albert:x:102:100::/home/albert:/bin/bash
$

La commande affiche toutes les lignes contenant la chaîne bert (et non le mot bert). Si l’on souhaite la chaîne cherchée en début de ligne, on utilisera la syntaxe ′′^chaîne_cherchée′′. Si on la veut en fin de ligne : ′′chaîne_cherchée$′′

 
Sélectionnez
$ grep ′′^bert′′ pass
bertrand:x:101:100::/home/bertrand:/bin/bash
$

La commande unix grep positionne un code de retour

  • égal à 0 pour indiquer qu'une ou plusieurs lignes ont été trouvées
  • égal à 1 pour indiquer qu'aucune ligne n'a été trouvée
  • égal à 2 pour indiquer la présence d'une erreur de syntaxe ou qu'un fichier mentionné en argument est inaccessible.
 
Sélectionnez
$ grep sanchis pass
sanchis:x:103:100::/home/sanchis:/bin/bash
$ echo $?
0
$ grep toto pass
$ echo $?
1			       => la chaîne toto n'est pas présente dans pass
$ grep sanchis turlututu
grep: turlututu: Aucun fichier ou répertoire de ce type
$ echo $?
2                              => le fichier turlututu n'existe pas !
$

Exercice :
Ecrire un programme shell connu prenant en argument un nom d’utilisateur qui affiche 0 s’il est enregistré dans le fichier pass, 1 sinon.

 
Sélectionnez
$ connu bert
1
$ connu albert
0
$

VII-2. Code de retour d'un programme shell

Le code de retour d'un programme shell est le code de retour de la dernière commande qu'il a exécutée.

Soit le programme shell lvi contenant l'unique commande ls vi.

 
Sélectionnez
#!/bin/bash
#     @(#)     lvi
ls vi

Cette commande produira une erreur car vi ne se trouve pas dans le répertoire courant ; après exécution, le code de retour de lvi sera de celui de la commande ls vi (dernière commande exécutée).

 
Sélectionnez
$ lvi
ls: vi: Aucun fichier ou répertoire de ce type
$ echo $?
2                       => code de retour de la dernière commande exécutée par lvi
                        => c.-à-d. ls vi
$

Autre exemple avec le programme shell lvi1 de contenu :

 
Sélectionnez
#!/bin/bash
#      @(#)     lvi1
ls vi
echo Fin

La dernière commande exécutée par lvi1 sera la commande interne echo qui retourne un code de retour égal à 0.

 
Sélectionnez
$ lvi1
ls: vi: Aucun fichier ou répertoire de ce type
Fin
$ echo $?
0		=> code de retour de la dernière commande exécutée par lvi (echo Fin)
$

Il est parfois nécessaire de positionner explicitement le code de retour d'un programme shell avant qu'il ne se termine : on utilise alors la commande interne exit.

VII-3. Commande interne exit

 
Sélectionnez
Syntaxe :       exit [ n ]

Elle provoque l'arrêt du programme shell avec un code de retour égal à n. Si n n'est pas précisé, le code de retour fourni est celui de la dernière commande exécutée. Soit le programme shell lvi2 :

 
Sélectionnez
#!/bin/bash
#     @(#)     lvi2
ls vi
exit 23
 
Sélectionnez
$ lvi2
ls: vi: Aucun fichier ou répertoire de ce type
$ echo $?
23	       => code de retour de exit 23
$

Le code de retour renvoyé par ls vi est 2 ; en utilisant la commande interne exit, le programme shell lvi2 positionne un code de retour différent (23).

VII-4. Code de retour d'une suite de commandes

Le code de retour d'une suite de commandes est le code de retour de la dernière commande exécutée.

Le code de retour de la suite de commandes cmd1 ; cmd2 ; cmd3 est le code de retour de la commande cmd3.

 
Sélectionnez
$ pwd ; ls vi ; echo bonjour
/home/sanchis
ls: vi: Aucun fichier ou répertoire de ce type
bonjour
$ echo $?
0                              => code de retour de echo bonjour
$

Il en est de même pour le pipeline cmd1 | cmd2 | cmd3. Le code de retour sera celui de cmd3.

 
Sélectionnez
$ cat pass | grep sanchis
sanchis:x:103:100::/home/sanchis:/bin/bash
$ echo $?
0                        => code de retour de grep sanchis
$

Il est possible d'obtenir la négation d'un code de retour d'un pipeline en plaçant le mot-clé ! devant celui-ci. Cela signifie que si le code de retour de pipeline est égal à 0, alors le code de retour de ! pipeline est égal à 1.

 
Sélectionnez
$ ! ls pass => le code de retour de ls passest égal à 0
pass
$ echo $?
1
$ ! cat pass | grep daemon
daemon:x:1:1:daemon:/usr/sbin:/bin/sh
$ echo $?
1
$

Inversement, si le code de retour de pipeline est différent de 0, alors celui de ! pipeline est égal à 0.

 
Sélectionnez
$ ! grep sanchis turlututu
grep: turlututu: Aucun fichier ou répertoire de ce type
$ echo $?
0
$

VII-5. Résultats et code de retour

On ne doit pas confondre le résultat d'une commande et son code de retour : le résultat correspond à ce qui est écrit sur sa sortie standard ; le code de retour indique uniquement si l'exécution de la commande s'est bien effectuée ou non.

Parfois, on est intéressé uniquement par le code de retour d'une commande et non par les résultats qu'elle produit sur la sortie standard ou la sortie standard pour les messages d'erreurs.

 
Sélectionnez
$ grep toto pass > /dev/null 2>&1 => ou bien : grep toto pass &>/dev/null
$ echo $?
1		                  => on en déduit que la chaîne toto n'est pas présente dans pass
$

VII-6. Opérateurs && et || sur les codes de retour

Les opérateurs && et || autorisent l’exécution conditionnelle d’une commande cmd suivant la valeur du code de retour de la dernière commande précédemment exécutée.

Opérateur : &&

 
Sélectionnez
Syntaxe :      cmd1 && cmd2

Le fonctionnement est le suivant : cmd1 est exécutée et si son code de retour est égal à 0, alors cmd2 est également exécutée.

 
Sélectionnez
$ grep daemon pass && echo daemon existe
daemon:x:1:1:daemon:/usr/sbin:/bin/sh
daemon existe
$

La chaîne de caractères daemon est présente dans le fichier pass, le code de retour renvoyé par l’exécution de grep est 0 ; par conséquent, la commande echo daemon existe est exécutée.

Opérateur : ||

 
Sélectionnez
Syntaxe :       cmd1 || cmd2

cmd1 est exécutée et si son code de retour est différent de 0, alors cmd2 est également exécutée. Pour illustrer cela, supposons que le fichier toto n’existe pas.

 
Sélectionnez
$ ls pass toto
ls: toto: Aucun fichier ou répertoire de ce type
pass
$
$ rm toto || echo toto non efface
rm: ne peut enlever `toto': Aucun fichier ou répertoire de ce type
toto non efface
$

Le fichier toto n’existant pas, la commande rm toto affiche un message d’erreur et produit un code de retour différent de 0 : la commande interne echo qui suit est donc exécutée.

Combinaisons d’opérateurs && et ||

Les deux règles mentionnées ci-dessus sont appliquées par le shell lorsqu'une suite de commandes contient plusieurs opérateurs && et ||. Ces deux opérateurs ont même priorité et leur évaluation s’effectue de gauche à droite.

 
Sélectionnez
$ ls pass || ls toto || echo fini aussi
pass
$

Le code de retour de ls pass est égal à 0 car pass existe, la commande ls toto ne sera donc pas exécutée. D’autre part, le code de retour de l’ensemble ls pass || ls toto est le code de retour de la dernière commande exécutée, c’est à dire est égal à 0 (car c’est le code de retour de ls pass), donc echo fini aussi n’est pas exécutée.

Intervertissons maintenant les deux commandes ls :

 
Sélectionnez
$ ls toto || ls pass || echo fini
ls: toto: Aucun fichier ou répertoire de ce type
pass
$

Le code de retour de ls toto est différent de 0, donc ls pass s’exécute. Cette commande renvoie un code de retour égal à 0, par conséquent echo fini n’est pas exécutée.

Combinons maintenant opérateurs && et || :

 
Sélectionnez
$ ls pass || ls toto || echo suite et && echo fin
pass
fin
$

La commande ls pass est exécutée avec un code de retour égal à 0, donc la commande ls toto n’est pas exécutée : le code de retour de l’ensemble ls pass || ls toto est égal à 0, la commande echo suite et n’est pas exécutée. Le code de retour de ls pass || ls toto || echo suite et est égal à 0, donc la commande echo fin est exécutée !

Bien sûr, un raisonnement analogue s’applique avec l’opérateur && :

 
Sélectionnez
$ ls pass   && ls toto && echo fini
pass
ls: toto:   Aucun fichier ou répertoire de ce type
$ ls toto   && ls pass && echo suite et && echo fin
ls: toto:   Aucun fichier ou répertoire de ce type
$ ls pass   && ls toto && echo suite et || echo fin
pass
ls: toto:   Aucun fichier ou répertoire de ce type
fin
$

précédentsommairesuivant

Ce document est issu de http://www.developpez.com et reste la propriété exclusive de son auteur. La copie, modification et/ou distribution par quelque moyen que ce soit est soumise à l'obtention préalable de l'autorisation de l'auteur.