Vous êtes ici :
Accueil Cours Administration Système La programmation Système avec Shell Le code de retour (exit statut)

La programmation Système avec Shell : Le code de retour (exit statut)

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.

 

 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).
 
Exemple :  

$ pwd
/home/tony
$ 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 !
$
 

 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 ?.
 
Exemple : 

$ pwd    =>   mise à zéro du paramètre spécial ?
/home/tony
$
$ 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.
 
Exemple : 

$ :   => 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.
 

Exemple : 

$ 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 :
 
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
tony:x:103:100::/home/tony:/bin/bash
 

La commande ci-dessous affiche toutes les lignes du fichier pass contenant la chaîne "tony".
 
 $ grep  tony  pass
tony:x:103:100::/home/tony:/bin/bash
$
 
Attention :  grep recherche une chaîne de caractères et non un mot.  
 
Exemple : 

$  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$″
 
Exemple : 

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

Exemple : 

$ grep tony pass
tony:x:103:100::/home/tony:/bin/bash
$
0
echo $?
$  
$ grep toto pass
$
$ echo $?

1    => la chaîne toto n'est pas présente dans pass
$  
$ grep tony turlututu

grep: turlututu: Aucun fichier ou répertoire de ce type
$  
$ echo $?

2    => le fichier turlututu n'existe pas !

 

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.  
 

#!/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).
 
Exemple :

$ 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 :
 

#!/bin/bash 
#    @(#)   lvi1 
ls vi 
echo terminer 

 

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

$ lvi1
ls: vi: Aucun fichier ou répertoire de ce type
terminer
$  
$ 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.
 

 

 Commande interne exit

 

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 :

#!/bin/bash 
#    @(#)   lvi2 
 
ls vi 
exit 23 

 

Exemple : 

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

 

 

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

$ pwd ; ls vi ; echo bonjour
/home/tony
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.
 
Exemple : 

$ cat pass | grep tony
tony:x:103:100::/home/tony:/bin/bash
$  
$ echo $?

0  => code de retour de grep tony
$
 
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.   

Exemple : 

$ ! ls pass  => le code de retour de ls pass est é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.
 
Exemple : 

$ ! grep tony turlututu
grep: turlututu: Aucun fichier ou répertoire de ce type
$
$ echo $?

0
$

 

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

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

Les 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 :   &&
 


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

$ 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 :   ||   
 

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

$ 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.
 
Exemple : 

$ 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 :
 
Exemple : 

$ 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 les opérateurs && et || :
 

Exemple :

$ 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 &&
 
Exemple : 

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

 




Vous êtes ici :
Accueil Cours Administration Système La programmation Système avec Shell Le code de retour (exit statut)