Script de shell de sortie basé sur le code de sortie du processus

J’ai un script shell qui exécute un certain nombre de commandes. Comment puis-je quitter le script shell si l’une des commandes se termine par un code de sortie différent de zéro?

Après chaque commande, le code de sortie peut être trouvé dans le $? variable de sorte que vous auriez quelque chose comme:

 ls -al file.ext rc=$?; if [[ $rc != 0 ]]; then exit $rc; fi 

Vous devez faire attention aux commandes de canalisation depuis le $? ne vous donne que le code retour du dernier élément dans le tube, donc dans le code:

 ls -al file.ext | sed 's/^/xx: /" 

ne renverra pas de code d’erreur si le fichier n’existe pas (puisque la partie sed du pipeline fonctionne réellement et renvoie 0).

Le shell bash fournit en fait un tableau pouvant aider dans ce cas, à savoir PIPESTATUS . Ce tableau a un élément pour chacun des composants du pipeline, auquel vous pouvez accéder individuellement, comme ${PIPESTATUS[0]} :

 pax> false | true ; echo ${PIPESTATUS[0]} 1 

Notez que cela vous permet d’obtenir le résultat de la commande false , pas le pipeline entier. Vous pouvez également traiter toute la liste comme bon vous semble:

 pax> false | true | false; echo ${PIPESTATUS[*]} 1 0 1 

Si vous voulez obtenir le plus grand code d’erreur d’un pipeline, vous pouvez utiliser quelque chose comme:

 true | true | false | true | false rcs=${PIPESTATUS[*]}; rc=0; for i in ${rcs}; do rc=$(($i > $rc ? $i : $rc)); done echo $rc 

Cela passe par chacun des éléments PIPESTATUS , en le stockant dans rc s’il était supérieur à la valeur rc précédente.

Si vous voulez travailler avec $?, Vous devrez le vérifier après chaque commande, depuis $? est mis à jour après chaque commande. Cela signifie que si vous exécutez un pipeline, vous obtiendrez uniquement le code de sortie du dernier processus dans le pipeline.

Une autre approche consiste à faire ceci:

 set -e set -o pipefail 

Si vous mettez ceci en haut du script shell, il semblerait que bash s’en charge pour vous. Comme l’a montré une affiche précédente, “set -e” provoquera la sortie de bash avec une erreur sur n’importe quelle commande simple. “set -o pipefail” provoquera la sortie de bash avec une erreur sur toute commande dans un pipeline.

Voir ici ou ici pour un peu plus de discussion sur ce problème. Voici la section du manuel bash sur l’ensemble intégré.

set -e ” est probablement la manière la plus simple de le faire. Il suffit de mettre cela avant toute commande dans votre programme.

Si vous appelez simplement exit dans le bash sans parameters, le code de sortie de la dernière commande sera renvoyé. Combiné avec OR, bash ne doit invoquer exit que si la commande précédente échoue. Mais je n’ai pas testé cela.

 command1 ||  Sortie;
 command2 ||  Sortie;

Le Bash stockera également le code de sortie de la dernière commande dans la variable $ ?.

 [ $? -eq 0 ] || exit $?; # exit for none-zero return code 

http://cfaj.freeshell.org/shell/cus-faq-2.html#11

  1. Comment puis-je obtenir le code de sortie de cmd1 dans cmd1|cmd2

    Tout d’abord, notez que le code de sortie de cmd1 peut être différent de zéro et ne signifie toujours pas une erreur. Cela se produit par exemple dans

     cmd | head -1 

    Vous pouvez observer un état de sortie 141 (ou 269 avec ksh93) de cmd1 , mais c’est parce que cmd été interrompu par un signal SIGPIPE lorsque head -1 arrêté après avoir lu une ligne.

    Pour connaître le statut de sortie des éléments d’un pipeline cmd1 | cmd2 | cmd3 cmd1 | cmd2 | cmd3

    une. avec zsh:

    Les codes de sortie sont fournis dans le tableau spécial pipestatus. cmd1 code de sortie est dans $pipestatus[1] , cmd3 code de sortie dans $pipestatus[3] , de sorte que $? est toujours le même que $pipestatus[-1] .

    b. avec bash:

    Les codes de sortie sont fournis dans le PIPESTATUS spécial PIPESTATUS . cmd1 code de sortie de cmd1 trouve dans ${PIPESTATUS[0]} , le code de sortie de cmd3 dans ${PIPESTATUS[2]} , de sorte que $? est toujours le même que ${PIPESTATUS: -1} .

    Pour plus de détails, voir le lien suivant.

pour bash:

 # this will trap any errors or commands with non-zero exit status # by calling function catch_errors() trap catch_errors ERR; # # ... the rest of the script goes here # function catch_errors() { # do whatever on errors # # echo "script aborted, because of errors"; exit 0; } 

En bash c’est facile, il suffit de les lier avec &&:

 command1 && command2 && command3 

Vous pouvez également utiliser la construction nestede if:

 if command1 then if command2 then do_something else exit fi else exit fi 
 # #------------------------------------------------------------------------------ # run a command on failure exit with message # doPrintHelp: doRunCmdOrExit "$cmd" # call by: # set -e ; doRunCmdOrExit "$cmd" ; set +e #------------------------------------------------------------------------------ doRunCmdOrExit(){ cmd="$@" ; doLog "DEBUG running cmd or exit: \"$cmd\"" msg=$($cmd 2>&1) export exit_code=$? # if occured during the execution exit with error error_msg="Failed to run the command: \"$cmd\" with the output: \"$msg\" !!!" if [ $exit_code -ne 0 ] ; then doLog "ERROR $msg" doLog "FATAL $msg" doExit "$exit_code" "$error_msg" else #if no errors occured just log the message doLog "DEBUG : cmdoutput : \"$msg\"" doLog "INFO $msg" fi } #eof func doRunCmdOrExit