====== 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]]