Warum geht while [0] in die Endlosschleife?

23

Ich sehe das gleiche Verhalten für die untere Schleife wie für die Schleife mit while [ 1 ]. Warum ist das so?

while [ 0 ]; do
    echo "hello"
done
user13107
quelle

Antworten:

33

Einzelne eckige Klammern in der Shell sind ein Synonym für test(entweder der separate Befehl oder die integrierte Shell) und [ 0 ]bedeuten dasselbe wie test 0. testdient zum Vergleichen und Testen der Attribute von Dateien, wie Sie in der Manpage lesen können. Wenn es keinen Ausdruck gibt, der aussieht wie ein Vergleich, ein Dateitest oder eine der anderen Operationen, die es ausführen kann, wird stattdessen geprüft, ob das Argument vorhanden ist und eine nicht leere Zeichenfolge. Weder 0noch 1sind wirklich geeignete Eingaben für den Test, und als nicht leere Zeichenfolgen ist der Test einfach erfolgreich, und Ihre while-Schleife wird für immer wiederholt.

Vielleicht möchten Sie es stattdessen versuchen

while false; do
  echo "hello"
done

möglicherweise ersetzen falsedurch true. Oder vielleicht möchten Sie Folgendes verwenden (( )):

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

Was sich wie die meisten Sprachen verhält, wobei 0 Fehlschlag / Falsch und 1 Erfolg / Wahr bedeutet.

wingedsubmariner
quelle
1
Betreff: "Wenn es keinen Ausdruck gibt, der aussieht wie ein Vergleich, ein Dateitest oder eine der anderen Operationen, die es ausführen kann, ist es einfach erfolgreich." Immerhin sind [ ](ohne Argument) und [ "" ](mit einem einzigen leeren Argument) nicht erfolgreich.
Ruakh
3
Wie @ruakh erklärt, ist diese Aussage falsch: Wenn es keinen Ausdruck gibt, der wie ein Vergleich, ein Dateitest oder eine der anderen Operationen aussieht, die es ausführen kann, ist es einfach erfolgreich. Jedes einzelne zu testende Argument (jedes einzelne Argument innerhalb der eckigen Klammern) wird als WAHR betrachtet, wenn das Argument keine leere Zeichenfolge und beide 0und 1keine leeren Zeichenfolgen sind. Neue Shell-Programmierer schreiben oft if [ 1=2 ]anstatt if [ 1 = 2 ]und fragen sich, warum das erstere immer wahr ist. Es ist wahr, weil es ein einzelnes Argument und keine leere Zeichenfolge ist.
Ian D. Allen
Gute Punkte, ich habe eine Korrektur vorgenommen.
Wingedsubmariner
10

Der Wert 0 wirkt hier nicht als numerische Konstante, sondern als Zeichenkette. Diese Tests haben alle die gleiche Wirkung auf einen erfolgreichen Kündigungsstatus:

[ A ]
[ "XYZ" ]
[ 0 ]

Diese führen zu einem fehlgeschlagenen Beendigungsstatus:

[ ]
[ "" ]

Es gibt ein nicht leeres Argument, das als logisch wahr ausgewertet wird. Auf diese Weise können Sie folgende Aufgaben ausführen:

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

Die Variable UNDER_NUCLEAR_ATTACKwird auf einen beliebigen nicht leeren Wert gesetzt, um "wahr" anzuzeigen, oder ist nicht gesetzt oder leer, um "falsch" anzuzeigen.

Wir können den !Operator anwenden , um die Logik umzukehren:

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

Um eine numerische Bedingung auszuwerten, müssen Sie numerische Testoperatoren verwenden:

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

Wenn Aund BZeichenfolgen enthalten, die wie Dezimalzahlen aussehen, werden sie wie Zahlen verglichen, und wenn Agrößer als B, wird die Schleife ausgeführt. Nehmen wir also an, dies UNDER_NUCLEAR_ATTACKist kein Boolescher Wert vom Typ String, der leer oder nicht leer ist, sondern ein numerischer Boolescher 0Wert , der entweder (false) oder ein anderer Wert (true) ist. In diesem Fall würden wir den Test folgendermaßen schreiben:

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

Ein if / then-Konstrukt testet, ob der Beendigungsstatus einer Befehlsliste 0 ist (da 0 gemäß UNIX-Konvention "Erfolg" bedeutet), und führt in diesem Fall einen oder mehrere Befehle aus.

Kurz gesagt, Sie geben ein Testergebnis von Null zurück.

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

Stephan
quelle
5
Ja, aber nicht aus dem Grund, den Sie zu denken scheinen. Wenn [nur ein Argument abgerufen ]wird (natürlich ohne das ), wird es mit dem Status Null beendet, wenn das Argument nicht leer ist, und wenn es nicht null ist. So wird beispielsweise [ 1 ]auch ein Exit-Code von zurückgegeben 0.
Kevin
-1

Der Wert 0 gilt als wahr für die while-Schleife, daher ist die Bedingung für while-Schleife wahr und daher stetig, um die Endlosschleife anzuzeigen. Das ist wahr, wenn wir 0 durch 1 ersetzen, da jede ganze Zahl, die wir zwischen die Bedingung schreiben, true zurückgibt

Jyoti Minhas
quelle