====== Script bash : état de sortie et les tests ====== * Objet : Script bash : enchaînement de commandes et redirection * Niveau requis : {{tag>débutant avisé}} * Commentaires : FIXME * Débutant, à savoir : [[:doc:systeme:commandes:le_debianiste_qui_papillonne|Utiliser GNU/Linux en ligne de commande, tout commence là !.]] :-) * Suivi : * Création par [[user>Hypathie]] le 18/03/2014 * Testé par [[user>Hypathie]] le Juin 2014 * Commentaires sur le forum : [[https://debian-facile.org/viewtopic.php?pid=142600#p142600 | Lien vers le forum concernant ce tuto]] ((N'hésitez pas à y faire part de vos remarques, succès, améliorations ou échecs !)) Contributeurs, les FIXME sont là pour vous aider, supprimez-les une fois le problème corrigé ou le champ rempli ! **Nota : Les autres wiki :** * [[doc:programmation:shells:debuter-avec-les-scripts-shell-bash]] * [[doc:programmation:shells:script-bash-variables-arguments-parametres|script-bash-variables-arguments-parametres]] * [[doc:programmation:shells:script-bash-detail-sur-les-parametres-et-les-boucles|modification de variable et de paramètre]] * [[doc:programmation:shells:script-bash-enchainement-de-commandes-et-etat-de-sortie|script-bash-enchainement-de-commandes-et-etat-de-sortie]] * ;-) * [[doc:programmation:shells:tableaux|script-bash-les-tableaux]] * [[doc:programmation:shells:fonction|script-bash-les-fonctions]] ===== État de sortie et code de retour===== ==== Le code de retour ==== Il ne faut pas confondre le code de retour et le résultat d'une commande. Le résultat est ce qui s'inscrit sur la sortie standard. - L'exécution de tous programmes et de toutes fonctions renvoie une valeur numérique appelée code de retour. - Il est envoyé ''0'' si tout c'est bien passé lors de l'exécution, et un nombre entre ''1 et 255'' s'il y a eu une erreur. - Pour récupérer le code de retour on utilise le paramètre spécial ''$?''. - Il y a des codes de retour particuliers, par exemple : blabla echo $? 127 >On peut chercher dans les codes d'erreur de bash que ''127'' est le code de retour pour les commandes qui n'ont pas pu être trouvées. L'état de sortie vrai ou faux ( 0 ou autre chose) est utilisé avec : - enchaînements conditionnels : - les tests ( commande ''test'', ''[[ ]]'', ''if/else'', ''case'') ==== L'enchaînement conditionnel est fondé sur le code de retour==== Parmi les opérateurs d'enchaînement de commandes ci-dessous :\\ (voir : [[doc:programmation:shells:bash-les-differents-caracteres-speciaux#Les opérateurs de contrôle|les opérateurs de contrôle]]) || && ; ceux fonctionnant sur le code de retour, sont : - l'opérateur ''et'', ''cmd1 && cmd2'' : avec cet opérateur, la commande 2 est exécutée si le code retour de la commande 1 est ''0'' (c'est-à-dire, si elle a fonctionné). - l'opérateur ''ou'', ''cmd1 || cmd2'' : la commande 2 est exécutée si le code de retour de la première est __différente de zéro__, c'est-à-dire si elle n'a pas fonctionné. * Exemple : Soit le dossier "Mon-dossier" non-vide; le dossier "mon-dossier" vide; et le dossier "mondossier" inexistant. #!/bin/bash cd ~/Mon-dossier && ls # => titi toto cd ~/mon-dossier || pwd # pas de retour : la première commande renvoie 0 # car "rester sur place" n'est pas une erreur cd ~/mondossier 2>/dev/null ||\ echo "le dossier mondossier n'existe pas" &&\ read -p "voulez-vous le créer [oui/non] ? " reponse &&\ ( [ $reponse == non ] && echo " le dossier ne sera pas créé") ||\ ( [ $reponse == oui ] && echo " le dossier va être créé" ) #; && mkdir ~/mondossier >Les antislash ne sont pas obligatoires, ils servent à rendre plus lisible les longues commandes qui se suivent sur une ligne. >On inhibe là le '''' ! Les opérateurs ''&&'' et ''||'' s'utilisent comme les opérateurs binaires.\\ Avec eux eux, c'est soit ''0'' soit autre chose que ''0'', c'est-à-dire ''1'', ou encore soit vrai, soit faux.\\ Voir la liste des [[doc:programmation:shells:page-man-bash-iv-symboles-dans-les-calculs-mathematiques#operateurs-binaires|opérateurs binaires]] ====Inverser le code de retour de la sortie d'une commande==== ! commande * Exemple : whoami echo $? 0 ! whoami echo $? 1 ==== Utiliser la commande exit ==== * Syntaxe : ''exit nombre'' >Avec un nombre de 1 à 3 chiffre(s). ===La commande "exit" === ''exit'' permet de remplacer le code de retour de la dernière commande d'un script. * Exemples : Dans ce script, puisque la correspondance est juste, la commande "exit 1" est exécutée, et on sort du programme. var=bonjour if [ $var == bonjour ] ; then echo "$var est correspond à bonjour" exit 1 fi bonjour est correspond à bonjour ./mon-script echo $? 1 ==="exit" force à sortir du programme=== #!/bin/bash var=bonjour if [ $var == coucou ] ; then echo "$var est correspond à coucou" exit 0 else echo "$var ne correspond pas à coucou" echo $? exit 1 echo $? fi echo "$var" bonjour ne correspond pas à coucou 0 ==="exit" et les paramètres passés au script === Lançons ce script avec aucun argument ou un autre que "a". #!/bin/bash if [[ $1 == a ]] ; then exit 1 fi echo "On a pas utilisé le bon argument, le test n'a pas permis d'exécuter exit" exit 0 On a pas utilisé le bon argument, le test n'a pas permis d'exécuter exit ===Convention et sortie de programme par défaut=== >Par convention on finit un script par ''exit 0'' > >Si on ne finit pas par ''exit 0'', il s'exécute un ''exit $?'' par défaut, ce qui est équivalent à un ''exit'' (tout court). #!/bin/bash var=bonjour echo "$var" echho " " 2>/dev/null # affichage d'erreur vers le puits echo $? exit 13 bonjour 127 * Ou encore : echo $? 13 ===== État de sortie et les tests===== ===À savoir :=== * [[doc:programmation:shells:la-page-man-bash-ii-les-operateurs-lexicographiques|les opérateurs lexicographiques]] et leur syntaxe * [[doc:programmation:shells:page-man-bash-iii-les-operateurs-de-comparaison-numerique|les opérateurs de comparaison numérique et leur syntaxe]] * La commande test ou les crochets :[[doc:programmation:shells:page-man-bash-iii-les-operateurs-de-comparaison-numerique#conclusion-sur-les-operateurs-lexicographiques-et-les-operateurs-de-comparaison-numerique]] **Attention au signe ''=''** Ne pas confondre le signe ''='' de l'affectation d'une variable par une valeur (voir ci-dessus [[doc:programmation:shells:debuter-avec-les-scripts-shell-bash#affectation-directe|affectation directe]])\\ avec l'opérateur de correspondance ''='' (ou ''=='' ) utilisé dans les tests.\\ Dans les tests sur les entiers l'égalité est représentée par l'option ''-eq'' ! ====Composition avec les tests; valeurs (vides ou nulles) déclarées dans le script ==== De même que la composition de commandes vu plus haut, on se sert de la composition avec les tests. Et oui les doubles crochets et la commande test sont des commandes ! LOL * séquentielle : ''cmd1 ; cmd2'' * parallèle : ''cmd1 & cmd2'' * sur erreur (ou) : ''cmd1 || cmd2'' * sur succès (et) : ''cmd1 && cmd2'' * rappel des options des commandes de test : - ''-z $chaine'' : teste si la variable ne contient rien - ''-n $chaine'' : teste si la variable contient quelque-chose #!/bin/bash #var3 est nulle, non déclarée, (ou non initialisée) : sa valeur est nulle #var2 est initialisée mais sans valeur : sa une valeur vide var1=ma_variable var2= var2bis=" " [ ${var1} ] && echo "$var1" # => ma_variable [ -n ${var1} ] && echo "$var1" # => ma_variable [ -n $var1 ] && echo "$var1" # => ma_variable #ou encore : test $var1 && echo "ok" # => ok test -n $var1 && echo "ok var1 contient quelque-chose" # => ok var1 contient quelque-chose test -z $var1 || echo "NON: var1 ne contient pas rien" # => NON: var1 ne contient pas rien echo " " [ -z $var2 ] && echo "var2: ${#var2} a une valeur vide : ne contient rien" # => var2: 0 a une valeur vide : ne contient rien [ -n $var2 ] && echo "var2: une valeur vide contient 0 : du vide !" # => var2: une valeur vide contient 0 : du vide ! [ -z $var2bis ] && echo "var2bis: comme var2" # => var2bis: comme var2 [ -n $var2bis ] && echo "var2bis: comme var2" # => var2bis: comme var2 echo " " [ -n $var3 ] && echo "ET avec -n: une variable nulle contient aussi du vide" # => ET avec -n: une variable nulle contient aussi du vide [ -n $var3 ] || echo "OU avec -n" # PAS DE RETOUR puisque la première commande a renvoyé le code de retour 0. [ -z $var3 ] && echo " OU avec -z une variable nulle contient aussi du vide" # => OU avec -z une variable nulle contient aussi du vide [ -z $var3 ] || echo " OU avec -z" # PAS DE RETOUR puisque la première commande a renvoyé le code de retour 0. ====Tests sur paramètres passés au scripts==== ===Alternatives : case et paramètres passés aux scripts=== Attention, ''case'' n'utilise pas d'expression régulière, il s'agit plutôt de "pattern matching".\\ Voir : [[http://bash.leyan.org/Cours+5+-+bash+II#Structure_conditionnelle_i_case_i_| les symboles reconnus par cases sont ceux servant à la manipulation des fichiers]]. * syntaxe de case : case $variable in expression) instructions ;; ... esac * Explications : - case "teste" la valeur du paramètre passé au script avec chaque "expression" ; - et en fonction de la réussite ou de l'échec du test, il y a exécution ou non des commandes placées au niveau de "instructions" ; - Case sert à conditionner l'exécution des commandes en fonction d'argument choisi ; - On se sert de "l'étoile" pour permettre que soit exécuter quelque chose quand n'importe quel autre paramètre que ceux des expressions, est passé au script; * Ne pas oublier : - le double point virgule qui permet de clôturer chaque test ; - esac pour finir. * exemple : #!/bin/bash # passer le paramètre 'coco' à ce script ; puis 'cucu' ; titi puis toto, puis celui que voulez. case $1 in coco) echo "Vous avez passé le paramètre 'coco', ré-essayez avec 'cucu'" ;; cucu) echo "Vous avez passé le paramètre 'cucu'" echo "un peu d'humour !" echo "Ré-essayé avec titi, puis avec toto." ;; titi|toto) echo "vous avez passé le paramètre $1" ;; *) echo "Vous avez choisi $1" esac Vous avez tout en mains pour comprendre ceci : [[doc:programmation:shell:avancee#selecteur-case|Fonctionnalités avancées du Shell: selecteur-case]] ===if et les paramètres passés au script=== Voir [[doc:programmation:shell:avancee#instruction-conditionnelle-if|structure conditionnelle if]] pour ce qui suit. Un script peut opérer un test sur les chaînes de caractères passées au script depuis le terminal. Ci-dessous, les valeurs de la variable1 (var1) et de la variable2 (var2) peuvent être les arguments passés au script. //(Lancez "mon-script" successivement sans argument, puis un, deux trois, etc. arguments.)// #!/bin/bash var1=$1 var2=$2 echo $1 echo $2 if [ $# == 1 ] ; then echo "ERREUR: vous avez entré $@, mais il faut deux arguments !" elif [ $# == 2 ] ; then echo "Les deux arguments que vous avez entré sont $1 et $2" elif [ $# == 0 ] ; then echo "ERREUR: vous n'avez pas entré d'arguments, il en faut deux !" fi ====Tests sur les valeurs déclarées dans le script==== === Avec la structure conditionnelle if === Avec la structure conditionnelle if, on peut aussi faire des tests sur la (les) valeur(s) déclarée(s) dans le script. #!/bin/bash var1=23 var2=36 if [ $var1 -eq $var2 ] ; then echo "$var1 et $var2 sont égales" else echo "$var1 et $var2 ne sont pas égales" fi if [ $var1 != $var2 ] ; then echo "$var1 et $var2 sont inégales" fi if [ ${#var1} = ${#var2} ] ; then echo "$var1 et $var2 sont des chaînes de même longueur" fi echo "les longueurs sont de : ${#var1} et de : ${#var2}" ===Conclusion === Les chaînes testées par un script peuvent être aussi le contenu d'un fichier.\\ * Voir ce script : [[http://www.quennec.fr/linux/programmation-shell-sous-linux/les-bases-de-la-programmation-shell/ex%C3%A9cution-de-tests/la-5]] Avec if + $paramètre ; case ; et l'utilisation de la commande test, les valeurs des variables que l'on testent dans le script peuvent être passées depuis l'extérieur du script, ou par déclaration/affectation dans le script, avant le(s) test(s).\\ Pour modifier la valeur d'une variable d'un script (que le script appelle une valeur extérieure; chaîne de caractère donnée par le terminale, récupération du résultat d'une commande, contenu d'un fichier, etc. ou que cette variable soit affectée dans le script lui-même) on utilise les boucles [[doc:programmation:shell:avancee#boucle-tant-que-while|while]] et [[doc:programmation:shell:avancee#boucle-pour-tout-for|for]].\\ On peut aussi modifier la valeur d'une variable d'un script, en exportant depuis le terminal une nouvelle valeur (voir [[doc:programmation:shells:script-bash-variables-arguments-parametres#exportation-de-la-valeur-d-une-variable|"export"]] ) =====La suite c'est ici===== [[doc:programmation:shells:tableaux|script-bash-les-tableaux]]