Je veux essayer un script simple
flag=false
while !$flag
do
read x
if [ "$x" -eq "true" ]
then
flag=true
fi
echo "${x} : ${flag}"
done
Mais quand je l'exécute, si je tape true
, je verrai cela x="true"
et flag="true"
, mais le cycle ne se termine pas. Quel est le problème avec le script? Comment inverser correctement une variable booléenne?
Réponses:
Il y a deux erreurs dans votre script. La première est que vous avez besoin d'un espace entre
!
et$flag
, sinon le shell recherche une commande appelée!$flag
. La deuxième erreur-eq
concerne les comparaisons d'entiers, mais vous l'utilisez sur une chaîne. En fonction de votre shell, soit vous verrez un message d'erreur et la boucle continuera indéfiniment car la condition[ "$x" -eq "true" ]
ne peut pas être vraie, soit chaque valeur non entière sera traitée comme 0 et la boucle se fermera si vous entrez une chaîne (y comprisfalse
) autre qu'un nombre différent de 0.Bien que ce
! $flag
soit correct, c'est une mauvaise idée de traiter une chaîne comme une commande. Cela fonctionnerait, mais il serait très sensible aux changements dans votre script, car vous devez vous assurer que$flag
cela ne peut jamais être quetrue
oufalse
. Il serait préférable d'utiliser une comparaison de chaînes ici, comme dans le test ci-dessous.Il y a probablement une meilleure façon d'exprimer la logique que vous recherchez. Par exemple, vous pouvez créer une boucle infinie et la rompre lorsque vous détectez la condition de terminaison.
la source
[
intégrée deksh
,[ x -eq y ]
retournez true si l'x
expression arithmétique se résout au même nombre que l'y
expression arithmétique, par exemple,x=2 true=1+1 ksh -c '[ x -eq true ] && echo yes'
elle afficherait oui.Bien qu'il n'y ait pas de variables booléennes dans Bash, il est très facile de les émuler en utilisant une évaluation arithmétique.
Cela fonctionne également dans ksh. Je ne serais pas surpris si cela fonctionne dans tous les shells compatibles POSIX, mais je n'ai pas vérifié la norme.
la source
! ! ((val))
dans Bash, comme en C ou C ++? Par exemple, sival
est 0, il reste 0 après! !
. Sival
est 1, il reste 1 après! !
. Sival
c'est 8, il est ramené à 1 après! !
. Ou dois-je poser une autre question?Si vous pouvez être absolument sûr que la variable contiendra 0 ou 1, vous pouvez utiliser l'opérateur XOR égal au niveau du bit pour basculer entre les deux valeurs:
la source
Cela fonctionne pour moi:
Mais, en fait, ce que vous devez faire est de remplacer le vôtre
while
par:la source
Il n'y a pas de concept de variable booléenne dans le shell.
Les variables du shell ne pouvaient être
text
(une chaîne), et que le texte dans certains cas , peut être interprété comme un entier (1
,0xa
,010
, etc.).Par conséquent, a
flag=true
n'implique aucune véracité ou fausseté du tout.Chaîne
Ce qui pourrait être fait est une comparaison de chaînes
[ "$flag" == "true" ]
ou utiliser le contenu variable dans une commande et vérifier ses conséquences , comme exécutertrue
(car il y a à la fois un exécutable appelétrue
et un appeléfalse
) comme commande et vérifier si le code de sortie de cette commande est nul (réussi).Ou plus court:
Si le contenu d'une variable est utilisé comme une commande, un
!
pourrait être utilisé pour annuler l'état de sortie de la commande, s'il existe un espace entre les deux (! cmd
), comme dans:Le script doit se changer en:
Entier
Utilisez des valeurs numériques et des extensions arithmétiques .
Dans ce cas, le code de sortie de
$((0))
is1
et le code de sortie de$((1))
is0
.En bash, ksh et zsh, l'arithmétique pourrait être effectuée à l'intérieur de a
((..))
(notez que le démarrage$
est manquant).flag=0; if ((flag)); then ... fi
Une version portable de ce code est plus compliquée:
Dans bash / ksh / zsh, vous pouvez faire:
Alternativement
Vous pouvez "Inverser une variable booléenne" (à condition qu'elle contienne une valeur numérique) comme:
((flag=!flag))
Cela changera la valeur
flag
soit0
ou1
.Remarque : veuillez vérifier les erreurs dans https://www.shellcheck.net/ avant de publier votre code sous forme de question, plusieurs fois cela suffit pour trouver le problème.
la source
until
est l'abréviation dewhile !
(etuntil
contrairement à!
Bourne), vous pouvez donc faire:Ce qui devrait être le même que:
Vous pouvez également l'écrire comme suit:
La partie entre le
until
/while
etdo
ne doit pas être une seule commande.!
est un mot-clé dans la syntaxe du shell POSIX. Il doit être délimité, un jeton séparé de ce qui suit et être le premier jeton qui a précédé un pipeline (! foo | bar
annule le pipeline etfoo | ! bar
n'est pas valide bien que certains shells l'acceptent comme une extension).!true
est interprétée comme la!true
commande qui a peu de chances d'exister.! true
devrait marcher.!(true)
devrait fonctionner dans des shells compatibles POSIX!
car il est délimité car il est suivi d'un(
jeton, mais en pratique, il ne fonctionne pas dansksh
/bash -O extglob
où il entre en conflit avec l'!(pattern)
opérateur glob étendu ni dans zsh (sauf dans l'émulation sh) où il entre en conflit avecglob(qualifiers)
etbareglobqual
etglob(group)
sans pour autant.la source
ou même:
devrait faire le travail
la source