it-swarm.com.de

Zwischen while und do im Shell-Skript

Ich habe das folgende Skript, das gut funktioniert:

!/bin/bash

a=12
while [ $a -gt 10 ]
do
    echo "$a"
    a=$(($a-1))
done
echo "done"

Wenn ich Zeile "Echo etwas" über "do" hinzufüge, erwarte ich einen Syntaxfehler in dieser Zeile. Es scheint, dass [ $a -gt 10 ] wird umgangen und es wird eine Endlosschleife. Wie konnte das passieren?

15
Geek

Von das Bash-Handbuch :

while

Die Syntax des Befehls while lautet:

while  Testbefehle; do  konsequente Befehle; 
 erledigt
Führen Sie consequent-commands Aus, solange test-commands Den Exit-Status Null hat. Der Rückgabestatus ist der Beendigungsstatus des zuletzt in consequent-commands Ausgeführten Befehls oder Null, wenn keiner ausgeführt wurde.

Hinweis: test-commands, Plural. Sie können im Test mehrere Befehle verwenden. Dies ist also eine vollkommen gültige Schleife mit der Liste der Befehle [ $a -gt 10 ]; echo "$a" Als Test:

while [ $a -gt 10 ]
echo "$a"
do
   a=$(($a-1))
done

Während der Befehl [ $a -gt 10 ] Fehlschlagen kann oder nicht, wird das echo (fast) immer erfolgreich sein (es sei denn, es konnte den Text nicht schreiben oder es ist ein anderer Fehler aufgetreten), so dass final Der Exit-Status der Testbefehle ist immer erfolgreich und die Schleife wird immer ausgeführt.

29
muru

Von man bash:

während Liste-1; mache Liste-2; erledigt
Der while-Befehl führt kontinuierlich die Liste aus list-2
solange der letzter Befehl in der Liste list-1
gibt einen Exit-Status von Null zurück.

Dies impliziert, dass ein list mehrere Befehle enthalten kann, was es tut (meistens durch Semikolons oder Zeilenumbrüche getrennt).

Das funktioniert also perfekt:

#!/bin/bash

a=12

while 
    echo something
    echo "a before test =  $a"
    [ a -gt 10 ]
do
    echo "a after test =  $a"
    a=$(($a-1))
done
echo "done"

Wenn der letzte Befehl vor dem do Echo ist, ist der Exit-Code, den der Empfang erhält, immer wahr (0) und die Schleife wird unendlich.

10
Isaac

Was die anderen Antworten hier implizieren, aber nicht explizit sagen, ist, dass [ ist ein eingebauter Befehl, kein syntaktischer Teil der Anweisung while.

Versuchen Sie, help [ an Ihrer Kommandozeile:

[: [ arg ... ]
Bewerten Sie den bedingten Ausdruck.

Dies ist ein Synonym für den eingebauten "Test", aber das letzte Argument muss
sei ein wörtliches ], passend zur Eröffnung [.

Ihr Skript lautet also gena als:

!/bin/bash
a=12
while test $a -gt 10
do
  echo "$a"
  a=$(($a-1))
done
echo "done"

Was Sie ändern zu:

!/bin/bash
a=12
while test $a -gt 10; echo something
do
  echo "$a"
  a=$(($a-1))
done
echo "done"
4
Paul Evans

Als Beispiel dafür, dass dies extrem ist, enthält/usr/bin/tzselect normalerweise etwa 70 Codezeilen zwischen dem while und dem do der Hauptschleife, die case-Anweisungen und Befehlssubstitution enthalten und eine einzelne Zeile zwischen do und done.

4
icarus

(als Ergänzung zu anderen Antworten).

Die Verwendung mehrerer Befehle in der Bedingungsliste wird häufig verwendet, um eine Schleife ähnlich der do { blah; blah; } while (condition) von C zu implementieren. Hier wird die Bedingung am Ende der Schleife überprüft, sodass der Code in der Schleife mindestens einmal ausgeführt wird.

In sh würden Sie dies wie folgt tun:

while
  blah
  blah
  condition
do
  continue # or :
done

Obwohl andere Ansätze möglich sind wie:

while true; do
  blah
  blah
  condition || break
done

Oder:

continue=true
while "$continue"; do
  blah
  blah
  condition || continue=false
done
end=false
until "$end"; do
  blah
  blah
  condition || end=true
done
2