J'ai essayé de déclarer une variable booléenne dans un script Shell en utilisant la syntaxe suivante:
variable=$false
variable=$true
Est-ce correct? De plus, si je voulais mettre à jour cette variable, utiliserais-je la même syntaxe? Enfin, la syntaxe suivante pour utiliser les variables booléennes comme expressions est-elle correcte:
if [ $variable ]
if [ !$variable ]
Réponse révisée (12 février 2014)
the_world_is_flat=true
# ...do something interesting...
if [ "$the_world_is_flat" = true ] ; then
echo 'Be careful not to fall off!'
fi
Réponse originale
Mises en garde: https://stackoverflow.com/a/21210966/89391
the_world_is_flat=true
# ...do something interesting...
if $the_world_is_flat ; then
echo 'Be careful not to fall off!'
fi
De: Utilisation de variables booléennes dans Bash
La raison de la réponse d'origine est incluse ici parce que les commentaires avant la révision du 12 février 2014 ne concernent que la réponse d'origine et que de nombreux commentaires sont erronés lorsqu'ils sont associés à la réponse révisée. Par exemple, le commentaire de Dennis Williamson à propos de bash construit dans true
le 2 juin 2010 s’applique uniquement à la réponse originale, pas à la version révisée.
bool=true
if [ "$bool" = true ]
Je fais pas recommander la réponse acceptée1. Sa syntaxe est jolie mais elle a quelques défauts.
Disons que nous avons la condition suivante.
if $var; then
echo 'Muahahaha!'
fi
Dans les cas suivants2, cette condition sera évaluée à true et exécutera la commande imbriquée.
# Variable var not defined beforehand. Case 1
var='' # Equivalent to var="". Case 2
var= # Case 3
unset var # Case 4
var='<some valid command>' # Case 5
Généralement, vous souhaitez que votre condition soit évaluée à true uniquement lorsque votre variable "booléenne", var
dans cet exemple, est explicitement définie sur true. Tous les autres cas sont dangereusement trompeurs!
Le dernier cas (# 5) est particulièrement vilain, car il exécutera la commande contenue dans la variable (ce qui explique pourquoi la condition est évaluée à true pour les commandes valides.3, 4).
Voici un exemple inoffensif:
var='echo this text will be displayed when the condition is evaluated'
if $var; then
echo 'Muahahaha!'
fi
# Outputs:
# this text will be displayed when the condition is evaluated
# Muahahaha!
Citer vos variables est plus sûr, par exemple. if "$var"; then
. Dans les cas ci-dessus, vous devriez recevoir un avertissement indiquant que la commande est introuvable. Mais nous pouvons encore faire mieux (voir mes recommandations en bas).
Voir aussi l'explication de Mike Holt sur la réponse originale de Miku.
Cette approche a également un comportement inattendu.
var=false
if [ $var ]; then
echo "This won't print, var is false!"
fi
# Outputs:
# This won't print, var is false!
Vous vous attendez à ce que la condition ci-dessus soit évaluée à false, n'exécutant donc jamais l'instruction imbriquée. Surprise!
Citer la valeur ("false"
), citer la variable ("$var"
) ou utiliser test
ou [[
au lieu de [
ne fait aucune différence.
Voici comment je vous recommande de vérifier vos "booléens". Ils fonctionnent comme prévu.
bool=true
if [ "$bool" = true ]; then
if [ "$bool" = "true" ]; then
if [[ "$bool" = true ]]; then
if [[ "$bool" = "true" ]]; then
if [[ "$bool" == true ]]; then
if [[ "$bool" == "true" ]]; then
if test "$bool" = true; then
if test "$bool" = "true"; then
Ils sont tous à peu près équivalents. Vous devrez taper quelques touches de plus que les approches des autres réponses.5 mais votre code sera plus défensif.
man woman
serait toujours considéré comme une commande valide, même si aucune page de manuel de ce type n'existe.Il semble y avoir un certain malentendu ici à propos de la construction intégrée de Bash true
, et plus précisément à propos de la façon dont Bash développe et interprète les expressions entre crochets.
Le code dans réponse de mik n'a absolument rien à voir avec la construction intégrée de Bash true
, ni /bin/true
, ni aucune autre variante de la commande true
. Dans ce cas, true
n'est rien de plus qu'une simple chaîne de caractères et aucun appel à la commande/à la commande true
n'est jamais effectué, ni par l'affectation de variable, ni par l'évaluation de l'expression conditionnelle.
Le code suivant est fonctionnellement identique au code dans la réponse du miku:
the_world_is_flat=yeah
if [ "$the_world_is_flat" = yeah ]; then
echo 'Be careful not to fall off!'
fi
La différence seulement est que les quatre caractères comparés sont "y", "e", "a" et "h" au lieu de "t ',' r ',' u 'et' e '. C'est tout. Aucune tentative n'a été faite pour appeler une commande ou une commande nommée yeah
, et il n'y a pas non plus (dans l'exemple de miku) de traitement spécial en cours lorsque Bash analyse le jeton true
. C'est juste une chaîne, et une complètement arbitraire à cela.
Mise à jour (2014-02-19): Après avoir suivi le lien dans la réponse de miku, je vois maintenant d'où provient une partie de la confusion. La réponse de Miku utilise des crochets simples, mais le fragment de code vers lequel il se connecte n'utilise pas de crochets. C'est juste:
the_world_is_flat=true
if $the_world_is_flat; then
echo 'Be careful not to fall off!'
fi
Les deux extraits de code vont se comporter de la même manière, mais les crochets changent complètement ce qui se passe sous le capot.
Voici ce que Bash fait dans chaque cas:
Pas de crochets:
$the_world_is_flat
jusqu'à la chaîne "true"
."true"
en tant que commande.true
(intégrée ou /bin/true
, selon la version de Bash).true
(toujours 0) à 0. Rappelez-vous que dans la plupart des shells, un code de sortie égal à 0 indique un succès et toute autre indication à un échec.if
de l'instruction then
Supports:
$the_world_is_flat
jusqu'à la chaîne "true"
.string1 = string2
. L'opérateur =
est l'opérateur comparaison de chaînes de bash. Alors..."true"
et "true"
.if
de l'instruction then
.Le code sans crochets fonctionne, car la commande true
renvoie un code de sortie égal à 0, qui indique un succès. Le code entre crochets fonctionne, car la valeur de $the_world_is_flat
est identique au littéral de chaîne true
situé à droite du =
.
Juste pour conduire le point à la maison, considérons les deux extraits de code suivants:
Ce code (s'il est exécuté avec les privilèges root) va redémarrer votre ordinateur:
var=reboot
if $var; then
echo 'Muahahaha! You are going down!'
fi
Ce code affiche simplement "Bon essai". La commande de redémarrage n'est pas appelée.
var=reboot
if [ $var ]; then
echo 'Nice try.'
fi
Mise à jour (2014-04-14) Répondre à la question dans les commentaires concernant la différence entre =
et ==
: AFAIK , il n'y a pas de différence. L'opérateur ==
est un synonyme spécifique de Bash pour =
et, autant que je sache, ils fonctionnent exactement de la même manière dans tous les contextes.
Notez cependant que je parle spécifiquement des opérateurs de comparaison de chaînes =
et ==
utilisés dans les tests [ ]
ou [[ ]]
. Je ne suggère pas que =
et ==
soient interchangeables partout en bash.
Par exemple, vous ne pouvez évidemment pas assigner de variable avec ==
, tel que var=="foo"
(et bien techniquement vous pouvez le faire, mais la valeur de var
be "=foo"
, Bash ne voyant pas d'opérateur ==
ici, il voit un opérateur =
(affectation), suivi de la valeur littérale ="foo"
, qui devient simplement "=foo"
).
De plus, bien que =
et ==
soient interchangeables, vous devez garder à l’esprit que ces tests fonctionnent ne selon que vous l’utilisez à l'intérieur de [ ]
ou [[ ]]
, et aussi si les opérandes sont cités ou non. Pour en savoir plus à ce sujet, consultez Guide de script Bash avancé: 7.3 Autres opérateurs de comparaison (faites défiler jusqu'à la discussion sur =
et ==
).
Utilisez des expressions arithmétiques.
#!/bin/bash
false=0
true=1
((false)) && echo false
((true)) && echo true
((!false)) && echo not false
((!true)) && echo not true
Sortie:
vrai
pas faux
Longue histoire courte:
Ce que bash a, ce sont des expressions booléennes en termes de comparaison et de conditions. Cela dit, ce que vous pouvez déclarer et comparer dans bash sont des chaînes et des nombres. C'est tout.
Où que vous voyiez true
ou false
dans bash, il s’agit d’une chaîne ou d’une commande/intégrée qui n’est utilisée que pour son code de sortie.
Cette syntaxe ...
if true; then ...
est essentiellement ...
if COMMAND; then ...
La condition est vraie chaque fois que la commande retourne le code de sortie 0. true
et false
sont des commandes intégrées Bash et parfois aussi des programmes autonomes qui ne font que retourner le code de sortie correspondant.
La condition ci-dessus est équivalente à:
COMMAND && ...
Lorsque vous utilisez des crochets ou la commande test
, vous vous fiez au code de sortie de cette construction. Gardez à l'esprit que [ ]
et [[ ]]
sont également des commandes/fonctions intégrées comme les autres. Alors ...
if [[ 1 == 1 ]]; then echo yes; fi
correspond à
if COMMAND; then echo yes; fi
et la COMMAND
est ici [[ 1 == 1 ]]
La construction if..then..fi
est simplement un sucre syntaxique. Vous pouvez toujours simplement exécuter les commandes séparées par un double et commercial pour le même effet:
[[ 1 == 1 ]] && echo yes
Lorsque vous utilisez true
et false
dans ces constructions de test, vous ne faites que transmettre la chaîne "true"
ou "false"
à la commande testing. Voici un exemple:
Croyez-le ou non, mais toutes ces conditions donnent le même résultat:
if [[ false ]]; then ...
if [[ "false" ]]; then ...
if [[ true ]]; then ...
if [[ "true" ]]; then ...
Pour que cela soit clair pour les futurs lecteurs, je recommanderais de toujours utiliser des guillemets autour de true
et false
:
if [[ "${var}" == "true" ]]; then ...
if [[ "${var}" == "false" ]]; then ...
if [[ -n "${var:-}" ]]; then echo "var is not empty" ...
if [ ... ]; then ... # always use double square brackets in bash!
if [[ "${var}" ]]; then ... # this is not as clear or searchable as -n
if [[ "${var}" != true ]]; then ... # creates impression of booleans
if [[ "${var}" -eq "true" ]]; then ... # `-eq` is for numbers and doesn't read as easy as `==`
if [[ "${var}" != "true" ]]; then ... # creates impression of booleans. Can be used for strict checking of dangerous operations. This condition is false for anything but the literal string "true".
Il y a longtemps, alors que tout ce que nous avions était sh
, les booléens étaient gérés en utilisant une convention du programme test
où test
renvoyait un faux statut de sortie s'il était exécuté sans argument. Cela permet de penser à une variable non définie comme étant fausse et à une variable ayant la valeur vraie. Aujourd'hui, test est intégré à bash
et est généralement connu sous son alias à un caractère [
(ou un exécutable à utiliser dans les shells qui en sont dépourvus, comme le note dolmen):
FLAG="up or <set>"
if [ "$FLAG" ] ; then
echo 'Is true'
else
echo 'Is false'
fi
# unset FLAG
# also works
FLAG=
if [ "$FLAG" ] ; then
echo 'Continues true'
else
echo 'Turned false'
fi
En raison des conventions de citation, les auteurs de script préfèrent utiliser la commande composée [[
qui imite test
mais avec une syntaxe plus agréable: les variables avec des espaces n'ont pas besoin d'être citées, on peut utiliser &&
et ||
comme opérateurs logiques avec une étrange priorité, et il n'y a pas de POSIX limitations sur le nombre de termes.
Par exemple, pour déterminer si FLAG est défini et que COUNT est un nombre supérieur à 1:
FLAG="u p"
COUNT=3
if [[ $FLAG && $COUNT -gt '1' ]] ; then
echo 'Flag up, count bigger than 1'
else
echo 'Nope'
fi
Cela peut prêter à confusion lorsque des espaces, des chaînes de longueur nulle et des variables null sont nécessaires, ainsi que lorsque votre script doit fonctionner avec plusieurs shells.
Comment déclarer et utiliser des variables booléennes dans un script shell?
Contrairement à beaucoup d'autres langages de programmation, Bash ne sépare pas ses variables par "type". [1]
Donc, la réponse est assez claire. Il n'y a pas de boolean variable
dans bash . Cependant:
En utilisant une déclaration, nous pouvons limiter l’attribution de valeur aux variables. [2]
#!/bin/bash
declare -ir BOOL=(0 1) #remember BOOL can't be unset till this Shell terminate
readonly false=${BOOL[0]}
readonly true=${BOOL[1]}
#same as declare -ir false=0 true=1
((true)) && echo "True"
((false)) && echo "False"
((!true)) && echo "Not True"
((!false)) && echo "Not false"
L'option r
dans declare
et readonly
permet d'indiquer explicitement que les variables sont readonly. J'espère que le but est clair.
Au lieu de simuler un booléen et de laisser un piège aux futurs lecteurs, pourquoi ne pas simplement utiliser une valeur supérieure à true et false?
Par exemple:
build_state=success
if something-horrible; then
build_state=failed
fi
if [[ "$build_state" == success ]]; then
echo go home, you are done
else
echo your head is on fire, run around in circles
fi
Bill Parker est rejeté , car ses définitions sont inversées par rapport à la convention normale. Normalement, true est défini sur 0 et false sur non-zéro. 1 fonctionnera pour faux, de même que 9999 et -1. Idem avec les valeurs de retour de fonction - 0 est un succès et tout ce qui n'est pas nul est un échec. Désolé, je n'ai pas encore la crédibilité de la rue pour voter ou lui répondre directement.
Bash recommande d'utiliser les doubles crochets maintenant comme habitude plutôt que les crochets simples, et le lien donné par Mike Holt explique les différences de fonctionnement. 7.3. Autres opérateurs de comparaison
D'une part, -eq
est un opérateur numérique, donc avoir le code
#**** NOTE *** This gives error message *****
The_world_is_flat=0;
if [ "${The_world_is_flat}" -eq true ]; then
émettra une déclaration d'erreur, dans l'attente d'une expression entière. Ceci s’applique à l’un ou l’autre paramètre, puisqu’un n’est une valeur entière. Pourtant, si nous mettons des doubles crochets autour de cela, cela ne produira pas de déclaration d'erreur, mais cela produira une valeur erronée (enfin, dans 50% des permutations possibles). Il évaluera à [[0 -eq true]] = succès, mais aussi à [[0 -eq false]] = succès, ce qui est faux (hmmm .... et qu'en est-il de la valeur numérique?).
#**** NOTE *** This gives wrong output *****
The_world_is_flat=true;
if [[ "${The_world_is_flat}" -eq true ]]; then
Il y a d'autres permutations du conditionnel qui donneront également un résultat erroné. Fondamentalement, tout élément (autre que la condition d'erreur indiquée ci-dessus) qui définit une variable sur une valeur numérique et la compare à une valeur intégrée true/false ou définit une variable à une valeur intégrée true/false et la compare à une valeur numérique. En outre, tout ce qui définit une variable sur une valeur true/false et effectue une comparaison à l'aide de -eq
. Donc, évitez -eq
pour les comparaisons booléennes et évitez d'utiliser des valeurs numériques pour les comparaisons booléennes. Voici un résumé des permutations qui donneront des résultats invalides:
#With variable set as an integer and evaluating to true/false
#*** This will issue error warning and not run: *****
The_world_is_flat=0;
if [ "${The_world_is_flat}" -eq true ]; then
#With variable set as an integer and evaluating to true/false
#*** These statements will not evaluate properly: *****
The_world_is_flat=0;
if [ "${The_world_is_flat}" -eq true ]; then
#
if [[ "${The_world_is_flat}" -eq true ]]; then
#
if [ "${The_world_is_flat}" = true ]; then
#
if [[ "${The_world_is_flat}" = true ]]; then
#
if [ "${The_world_is_flat}" == true ]; then
#
if [[ "${The_world_is_flat}" == true ]]; then
#With variable set as an true/false builtin and evaluating to true/false
#*** These statements will not evaluate properly: *****
The_world_is_flat=true;
if [[ "${The_world_is_flat}" -eq true ]]; then
#
if [ "${The_world_is_flat}" = 0 ]; then
#
if [[ "${The_world_is_flat}" = 0 ]]; then
#
if [ "${The_world_is_flat}" == 0 ]; then
#
if [[ "${The_world_is_flat}" == 0 ]]; then
Alors, maintenant à ce qui fonctionne. Utilisez les expressions authentiques/fausses pour votre comparaison et vos évaluations (comme Mike Hunt l’a noté, ne les mettez pas entre guillemets). Ensuite, utilisez le signe simple ou double égal (= ou ==) et les crochets simples ou doubles ([] ou [[]]). Personnellement, j'aime bien le signe double égal, car il me rappelle les comparaisons logiques d'autres langages de programmation et les guillemets simplement parce que j'aime taper. Donc, ces travaux:
#With variable set as an integer and evaluating to true/false
#*** These statements will work properly: *****
#
The_world_is_flat=true/false;
if [ "${The_world_is_flat}" = true ]; then
#
if [[ "${The_world_is_flat}" = true ]]; then
#
if [ "${The_world_is_flat}" = true ]; then
#
if [[ "${The_world_is_flat}" == true ]]; then
Voilà.
Dans de nombreux langages de programmation, le type booléen est, ou est implémenté, un sous-type d'entier, où true
se comporte comme 1
et false
se comporte comme 0
:
Mathématiquement , l'algèbre booléenne ressemble à l'arithmétique entière modulo 2. Par conséquent, si une langue ne fournit pas le type booléen natif, la solution la plus naturelle et la plus efficace est d'utiliser des entiers. Cela fonctionne avec presque toutes les langues. Par exemple, dans Bash, vous pouvez faire:
# val=1; ((val)) && echo "true" || echo "false"
true
# val=0; ((val)) && echo "true" || echo "false"
false
man bash :
((expression))
L'expression est évaluée selon les règles décrites ci-dessous dans la section ÉVALUATION ARITHMÉTIQUE. Si la valeur de l'expression est non nulle, le statut de retour est 0; sinon, le statut de retour est 1. Cela correspond exactement à laisser "expression".
Je manque ici le point essentiel, la portabilité. C'est pourquoi mon en-tête a POSIX en lui-même.
En gros, toutes les réponses votées sont correctes, sauf qu'elles sont trop spécifiques à BASH -.
Je souhaite donc simplement ajouter davantage d’informations sur la portabilité.
Les crochets [
et ]
comme dans [ "$var" = true ]
ne sont pas nécessaires, vous pouvez les omettre et utiliser directement la commande test
:
test "$var" = true && CodeIfTrue || CodeIfFalse
Imaginez ce que ces mots true
et false
signifient pour Shell, testez-le vous-même:
echo $((true))
0
echo $((false))
1
Mais en utilisant des guillemets:
echo $(("true"))
bash: "true": syntax error: operand expected (error token is ""true"") sh (dash): sh: 1: arithmetic expression: expecting primary: ""true""
C'est la même chose pour:
echo $(("false"))
Le shell ne peut pas l'interpréter autrement qu'une chaîne. J'espère que vous comprenez à quel point le mot-clé approprié sans citations est bon.
Mais personne ne l'a dit dans les réponses précédentes.
Qu'est-ce que cela signifie? Eh bien, plusieurs choses.
Vous devriez vous habituer au fait que les mots-clés booléens sont en réalité traités comme des nombres, c'est-à-dire true
= 0
et false
= 1
, n'oubliez pas que toutes les valeurs non nulles sont traitées comme false
.
Comme ils sont traités comme des nombres, vous devriez les traiter comme ça aussi, c’est-à-dire que si vous définissez variable, dites:
var_a=true
echo "$var_a"
true
vous pouvez en créer une valeur opposée avec:
var_a=$((1 - $var_a))
echo "$var_a"
1
Comme vous pouvez le constater, Shell imprime la chaîne true
pour la première fois, mais depuis lors, tout fonctionne via le numéro 0
ou 1
, respectivement.
La première bonne habitude serait d’attribuer 0
au lieu de true
; 1
au lieu de false
.
La deuxième bonne habitude serait de vérifier si la variable est/n'est pas égale à zéro:
test "$var" -eq 0 && CodeIfTrue || CodeIfFalse
Voici une implémentation d'un if true
en désavantage numérique.
# Function to test if a variable is set to "true"
_if () {
[ "${1}" == "true" ] && return 0
[ "${1}" == "True" ] && return 0
[ "${1}" == "Yes" ] && return 0
return 1
}
Exemple 1
my_boolean=true
_if ${my_boolean} && {
echo "True Is True"
} || {
echo "False Is False"
}
Exemple 2
my_boolean=false
! _if ${my_boolean} && echo "Not True is True"
Voici un exemple simple qui fonctionne pour moi:
temp1=true
temp2=false
if [ "$temp1" = true ] || [ "$temp2" = true ]
then
echo "Do something."
else
echo "Do something else."
fi
Voici une amélioration par rapport à la réponse originale de miku , qui répond aux préoccupations de Dennis Williamson à propos du cas où la variable n'est pas définie:
the_world_is_flat=true
if ${the_world_is_flat:-false} ; then
echo "Be careful not to fall off!"
fi
Et pour vérifier si la variable est false
:
if ! ${the_world_is_flat:-false} ; then
echo "Be careful not to fall off!"
fi
À propos des autres cas avec un contenu désagréable dans la variable, il s'agit d'un problème avec toute entrée externe alimentant un programme.
Toute entrée externe doit être validée avant de lui faire confiance. Mais cette validation doit être effectuée une seule fois, lorsque cette entrée est reçue.
Il n’est pas nécessaire que la performance du programme soit influencée par chaque utilisation de la variable, comme le suggère William Williamson .
J'ai trouvé les réponses existantes déroutantes.
Personnellement, je veux juste avoir quelque chose qui ressemble et fonctionne comme C.
Cet extrait fonctionne plusieurs fois par jour en production:
snapshotEvents=true
if ($snapshotEvents)
then
# do stuff if true
fi
et pour que tout le monde soit heureux, j'ai testé:
snapshotEvents=false
if !($snapshotEvents)
then
# do stuff if false
fi
Ce qui a également bien fonctionné.
Le $snapshotEvents
évalue le contenu de la valeur de la variable. Donc, vous avez besoin du $
.
Vous n'avez pas vraiment besoin des parenthèses, je les trouve simplement utiles.
Testé sur: GNU Bash, version 4.1.11 (2) -release
Guide Bash pour les débutants , Machtelt Garrels, v1.11, 2008
Mes conclusions et ma suggestion diffèrent un peu des autres publications. J'ai trouvé que je pouvais utiliser true/false comme dans n'importe quel langage "normal", sans le "saut de hoop" suggéré ... Pas besoin de comparaisons de chaînes [] ou explicites ... J'ai essayé plusieurs distributions Linux, j'ai testé bash, dash et busybox. J'ai couru avec et sans elle frapper ... Les résultats ont toujours été les mêmes. Je ne suis pas sûr de ce dont parlent les articles les plus votés. Peut-être que les temps ont changé et que tout est là?
Si vous définissez une variable sur true
, sa valeur est true dans une condition. Définissez-la sur false
et sa valeur est false. Très simple! Le seul inconvénient est que la variableUNDEFINEDest également évaluée à true ! Ce serait bien si cela faisait l'inverse, mais c'est le truc - il vous suffit de définir explicitement vos booléens sur true ou false .
Voir l'exemple bash et les résultats ci-dessous. Testez-le vous-même si vous voulez confirmer ...
#!/bin/sh
#not yet defined...
echo "when set to ${myBool}"
if ${myBool}; then echo "it evaluates to true"; else echo "it evaluates to false"; fi;
myBool=true
echo "when set to ${myBool}"
if ${myBool}; then echo "it evaluates to true"; else echo "it evaluates to false"; fi;
myBool=false
echo "when set to ${myBool}"
if ${myBool}; then echo "it evaluates to true"; else echo "it evaluates to false"; fi;
Les rendements
when set to
it evaluates to true
when set to true
it evaluates to true
when set to false
it evaluates to false
Vous pouvez utiliser GFlags: https://gflags.github.io/gflags/
Il vous donne la possibilité de définir: DEFINE_bool
Exemple:
DEFINE_bool(big_menu, true, "Include 'advanced' options in the menu listing");
En ligne de commande, vous pouvez définir:
sh script.sh --bigmenu
sh script.sh --nobigmenu # False