Pourquoi alors que [0] entre en boucle infinie?

23

Je vois le même comportement pour la boucle ci-dessous que la boucle avec while [ 1 ]. Pourquoi est-ce si?

while [ 0 ]; do
    echo "hello"
done
user13107
la source

Réponses:

33

Les crochets simples dans le shell sont synonymes de test(soit la commande séparée, soit le shell intégré), ce qui [ 0 ]signifie donc la même chose que test 0. testsert à faire des comparaisons et à tester les attributs des fichiers, comme vous pouvez le lire dans sa page de manuel. Lorsqu'il ne reçoit pas d'expression qui ressemble à une comparaison, à un test de fichier ou à l'une des autres opérations qu'il peut effectuer, il testera plutôt si l'argument est présent et une chaîne non vide. Ni l'une 0ni l' autre ne 1sont des entrées vraiment appropriées pour le test, et comme le test de chaînes non vides réussit simplement et votre boucle while boucle pour toujours.

Vous voudrez peut-être essayer à la place

while false; do
  echo "hello"
done

remplaçant éventuellement falsepar true. Ou peut-être que vous voulez utiliser (( )):

while (( 0 )); do
  echo "hello"
done

Qui se comportera comme la plupart des langues, où 0 signifie échec / faux et 1 signifie succès / vrai.

wingedsubmariner
la source
1
Re: "Quand on ne lui donne pas une expression qui ressemble à une comparaison, un test de fichier ou l'une des autres opérations qu'il peut faire, il réussit simplement": je ne pense pas que ce soit une bonne façon de le dire. Après tout, [ ](sans argument) et [ "" ](avec un seul argument vide) ne réussissent pas .
ruakh
3
Comme l'explique @ruakh, cette affirmation est fausse: quand on ne lui donne pas une expression qui ressemble à une comparaison, à un test de fichier ou à l'une des autres opérations qu'il peut effectuer, elle réussit simplement. Tout argument unique à tester (tout argument unique entre crochets) est considéré comme VRAI si l'argument n'est pas une chaîne vide, et les deux 0et 1ne sont pas des chaînes vides. Les nouveaux programmeurs shell écrivent souvent à la if [ 1=2 ]place de if [ 1 = 2 ]et se demandent pourquoi le premier est toujours vrai. C'est vrai car c'est un seul argument et ce n'est pas une chaîne vide.
Ian D. Allen
Bon point, j'ai fait une correction.
wingedsubmariner
10

La valeur 0 ici n'agit pas comme une constante numérique, mais comme une chaîne de caractères. Ces tests sont tous équivalents dans leur effet de produire un statut de terminaison réussi:

[ A ]
[ "XYZ" ]
[ 0 ]

ceux-ci produisent un statut de fin d'échec:

[ ]
[ "" ]

il y a un argument non vide, qui est évalué comme vrai logique. Cela vous permet de faire des choses comme:

if [ $UNDER_NUCLEAR_ATTACK ] ; then
  launch-missiles -a $DRY_RUN  # $DRY_RUN set to "-n" during testing
fi

La variable UNDER_NUCLEAR_ATTACKest définie sur toute valeur non vide pour indiquer vrai, ou est non définie ou vide pour indiquer faux.

Nous pouvons appliquer l' !opérateur pour inverser la logique:

[ ! a ]  # fails: a is nonblank so true; and not true is false.
[ ! ]    # succeeds: blank is false, not blank is true.

Pour évaluer une condition numérique, vous devez utiliser des opérateurs de test numériques:

 while [ $A -gt $B ] ; do ...

Si Aet Bcontiennent des chaînes qui ressemblent à des nombres décimaux, elles sont comparées comme des nombres et si Aest supérieur à B, la boucle s'exécute. Supposons donc que ce UNDER_NUCLEAR_ATTACKne soit pas un booléen de type chaîne vide ou non vide, mais en fait un booléen numérique qui soit 0(faux) ou une autre valeur (vrai). Dans ce cas, nous écririons le test comme ceci:

 if [ $UNDER_NUCLEAR_ATTACK -ne 0 ] ; then ...
Kaz
la source
-1

Une construction if / then teste si l'état de sortie d'une liste de commandes est 0 (puisque 0 signifie "succès" par convention UNIX), et si c'est le cas, exécute une ou plusieurs commandes.

En bref, vous renvoyez un résultat de test nul.

http://www.tldp.org/LDP/abs/html/testconstructs.html

Stephan
la source
5
Oui, mais pas pour la raison pour laquelle vous semblez penser. Si [obtient un seul argument (excluant le ], bien sûr), il quitte avec le statut zéro si l'argument n'est pas vide, différent de zéro s'il l'est. Ainsi, par exemple, [ 1 ]retournera également un code de sortie de 0.
Kevin
-1

La valeur 0 est considérée comme vraie pour la boucle while donc la condition pour la boucle while est vraie et donc continue d'afficher la boucle infinie. Le est vrai si nous remplaçons 0 par 1, comme tout entier que nous écrivons entre la condition, il retournera vrai

Jyoti Minhas
la source