Emma2
Anmeldungsdatum: 28. Dezember 2018
Beiträge: 438
|
Ich verstehe noch nicht so richtig, was ich wann und wie mit Klammern oder Quotes einschließen muss.
Ich möchte konkret eine while-Schleife "unendlich" laufen lassen, bis eine Bedingung erfüllt ist, das geht ja ganz gut.
Zusätzlich möchte ich aber die Schleife mit einem Timeout abbrechen, wenn sie z.B. länger als eine Minute braucht. Versucht habe ich das so:
1
2
3
4
5
6
7
8
9
10
11
12 | timeout 60s
while :
do
if [ -z "$(vboxmanage list runningvms | grep -i $1)" ]
then
echo "$1 HAS stopped"
stopped="True"
break;
else
echo "$1 still running"
fi
done
|
Aber dieser Code tut nicht, was ich gern möchte. Wie kann ich den Timeout-Befehl auf die Schleife loslassen? Oder geht das eventuell gar nicht innerhalb eines Skriptes (weil die Schleife ja kein Prozess ist)? Und wenn nicht, gibt es dann eine Alternative? Danke für Eure Nachhilfe!
|
user_unknown
Anmeldungsdatum: 10. August 2005
Beiträge: 17552
Wohnort: Berlin
|
Emma2 schrieb: Ich verstehe noch nicht so richtig, was ich wann und wie mit Klammern oder Quotes einschließen muss.
Ich möchte konkret eine while-Schleife "unendlich" laufen lassen, bis eine Bedingung erfüllt ist, das geht ja ganz gut.
Zusätzlich möchte ich aber die Schleife mit einem Timeout abbrechen, wenn sie z.B. länger als eine Minute braucht. Versucht habe ich das so:
1
2
3
4
5
6
7
8
9
10
11
12 | timeout 60s
while :
do
if [ -z "$(vboxmanage list runningvms | grep -i $1)" ]
then
echo "$1 HAS stopped"
stopped="True"
break;
else
echo "$1 still running"
fi
done
|
Aber dieser Code tut nicht, was ich gern möchte. Wie kann ich den Timeout-Befehl auf die Schleife loslassen? Oder geht das eventuell gar nicht innerhalb eines Skriptes (weil die Schleife ja kein Prozess ist)? Und wenn nicht, gibt es dann eine Alternative? Danke für Eure Nachhilfe!
Die Bedingung einer For-Schleife darf zusammengesetzt sein und mehreres abprüfen. Wenn Du nicht 1000x pro Sekunde prüfen willst, ob das Script noch läuft, dann leg eine Pause ein (kommt mir vor, als ob ich das schon mal empfohlen hätte - beides). 1
2
3
4
5
6
7
8
9
10
11
12
13
14 | #!/bin/bash
stopped=0
for (( i = 0; (i < 60 && stopped == 0); i++ ))
do
if (( RANDOM%7 == 0 ))
then
echo "$i HAS stopped"
stopped=1
else
echo "$i"
fi
sleep 1
done
echo
|
Worte wie "True" oder "False" müsssen nicht mit Anführungsstrichen dekoriert werden. Sie enthalten weder Leerzeichen, an denen sie gesplittet werden können, noch sonstiges, das die Shell verwirren könnte. Viele User kommen mit einer Idee von Strings an, und sind es gewohnt in ihrer Sprache alle literalen Strings einzutütteln. Das soll dann magischerweise auch in der Shell was bringen. Es bringt nichts. Umgekehrt müssen Variablen, die Strings enthalten, oft maskiert werden. Das bringt aber die meisten nicht zum Nachdenken. Statt meines RANDOM nimmst Du Deine grep-Zeile. Grep hat auch die Option -q (quiet, leise) und liefert dann nur wahr/falsch, ob was gefunden wurde. While ist auch dafür da, Bedingungen zu prüfen. Break nimmt man nur, wenn man mit sauberen Mitteln nicht weiter weiß. Wenn Du kürzer als 1s warten willst, warte 0.5 und zähle bis 120 usw.
|
Emma2
(Themenstarter)
Anmeldungsdatum: 28. Dezember 2018
Beiträge: 438
|
user_unknown schrieb: Wenn Du nicht 1000x pro Sekunde prüfen willst, ob das Script noch läuft, dann leg eine Pause ein (kommt mir vor, als ob ich das schon mal empfohlen hätte - beides).
Janee, scho'klar, ich "bastele" momentan auch nur, weil ich mit der Syntax noch so schrecklich unsicher bin. Deshalb habe ich die Prüfung durchlaufen lassen, um zu "sehen", was passiert. user_unknown schrieb: Worte wie "True" oder "False" müsssen nicht mit Anführungsstrichen dekoriert werden.
Aber es gibt doch keine Booleans? Wenn ich die Anführungszeichen weglasse, werden dann True und False als Strings interpretiert? Ok, das wusste ich natürlich nicht. user_unknown schrieb: Grep hat auch die Option -q (quiet, leise) und liefert dann nur wahr/falsch, ob was gefunden wurde.
Oh, das wusste ich als Noch-Linux-Newbie auch nicht, ich lerne gerade erst, was grep für ein tolles Tool ist. Ich denke, dass ich damit eine Vorablösung "basteln" kann, danke. Allerdings - ich möchte ja auch was lernen - ist meine konkrete Frage nicht beantwortet: Warum funktioniert timeout nicht? Ich erkläre es mir so, dass timeout einen Prozess abbricht, nicht aber eine Funktion oder eine Schleife innerhalb eines Skripts. Kann das stimmen?
|
Emma2
(Themenstarter)
Anmeldungsdatum: 28. Dezember 2018
Beiträge: 438
|
user_unknown schrieb: Grep hat auch die Option -q (quiet, leise) und liefert dann nur wahr/falsch, ob was gefunden wurde.
Sähe meine Schleife dann so aus (Leerzeichen?):
1
2
3
4
5
6
7
8
9
10
11
12
13 | stopped=0
steps=60
while [ $stopped = 0 && $steps > 0 ]
do
if [ -z "$(vboxmanage list runningvms | grep -i $1)" ]
then
echo "$i HAS stopped"
stopped=1
else
sleep
--steps
fi
done
|
? ... und wie sieht dann die Bedingung mit grep -q aus?
|
Emma2
(Themenstarter)
Anmeldungsdatum: 28. Dezember 2018
Beiträge: 438
|
Hmm, irgendwie stehe ich mit der Syntax auf Kriegsfuß:
| while [ $stopped -eq 0 && $steps -gt 0 ]
do
|
liefert mir für die Zeile mit der Bedingung
| ./backup-vm.sh: 33: [: missing ]
|
Ein Doppelpunkt hinter der schließenden Eckigen hilft auch nicht. Ich denke, ich muss erst ein bisschen lesen... ☹ ... ist ja doch so ganz anders als C/C++, JAVA, C#...
|
user_unknown
Anmeldungsdatum: 10. August 2005
Beiträge: 17552
Wohnort: Berlin
|
Emma2 schrieb: user_unknown schrieb: Wenn Du nicht 1000x pro Sekunde prüfen willst, ob das Script noch läuft, dann leg eine Pause ein (kommt mir vor, als ob ich das schon mal empfohlen hätte - beides).
Janee, scho'klar, ich "bastele" momentan auch nur, weil ich mit der Syntax noch so schrecklich unsicher bin. Deshalb habe ich die Prüfung durchlaufen lassen, um zu "sehen", was passiert.
Das siehst Du mit "sleep 0.1" auch schnell genug, und es müllt Dir nicht den Bildschirm zu. Oder 0.3 vielleicht nicht.
user_unknown schrieb: Worte wie "True" oder "False" müsssen nicht mit Anführungsstrichen dekoriert werden.
Aber es gibt doch keine Booleans? Wenn ich die Anführungszeichen weglasse, werden dann True und False als Strings interpretiert? Ok, das wusste ich natürlich nicht.
Es hängt vom Kontext ab, aber nicht von Anführungsstrichen.
| echo True true false
echo "True true false"
echo "True" "true" "false"
|
geben alle das gleiche aus, und
wird versuchen, die Datei "true" auf den Bildschirm zu schreiben.
werden versuchen, einen Host namens "true" anzupingen etc.
user_unknown schrieb: Grep hat auch die Option -q (quiet, leise) und liefert dann nur wahr/falsch, ob was gefunden wurde.
Oh, das wusste ich als Noch-Linux-Newbie auch nicht, ich lerne gerade erst, was grep für ein tolles Tool ist. Ich denke, dass ich damit eine Vorablösung "basteln" kann, danke. Allerdings - ich möchte ja auch was lernen - ist meine konkrete Frage nicht beantwortet: Warum funktioniert timeout nicht? Ich erkläre es mir so, dass timeout einen Prozess abbricht, nicht aber eine Funktion oder eine Schleife innerhalb eines Skripts. Kann das stimmen?
Tja - das weiß ich auch nicht. Lt. --help:
| timeout --help
Aufruf: timeout [OPTION] ZEITSPANNE BEFEHL [ARGUMENT]...
oder: timeout [OPTION]
Starte BEFEHL und beende ihn zwangsweise, wenn er nach ZEITSPANNE noch läuft.
|
muss einer Zeitspanne auf jeden Fall ein Befehl folgen. Du hattest da nichts stehen, damit ist es ein Syntaxfehler. Ich meine aber, dass Deine Vermutung richtig ist, und man keine Funktion mit timeout aufrufen kann. Man kann aber natürlich ein externes Script aufrufen. Command könnte natürlich auch etwas wie "for" sein, aber das quittiert das Terminal unnachsichtig und prompt: | timeout 3s for in in 1 2 3 4
timeout: der Befehl »for“ konnte nicht ausgeführt werden: Datei oder Verzeichnis nicht gefunden
|
|
user_unknown
Anmeldungsdatum: 10. August 2005
Beiträge: 17552
Wohnort: Berlin
|
Emma2 schrieb: Hmm, irgendwie stehe ich mit der Syntax auf Kriegsfuß:
| while [ $stopped -eq 0 && $steps -gt 0 ]
do
|
Ja, die Bash ist schon furchtbar. Wenn sie nicht so praktisch wäre ... Allerdings will mir nicht in den Kopf, wieso Du mit Gewalt eine while-Loop benutzen willst, und arithmetische Ausdrücke in den Backsteinklammern. Die For-Loop bietet genau was Du brauchst; (Initialisierung; Bedingung; In-/Dekrement), und das ist wie in C, C++ und Java: | for ((stopped=0, steps=6; stopped == 0 && steps > 0; --steps )); do echo -n ".$steps" ; done; echo
|
liefert mir für die Zeile mit der Bedingung
| ./backup-vm.sh: 33: [: missing ]
|
Ja, die Bash hat 4 Konstrukte für Bedingungen, [, [[, (( und ohne. Ich muss immer nachschauen, was mit [ und [[ los ist und vermeide sie, wo es geht. Die doppelten, runden Klammern, ohne Blank dazwischen, sind für Zahlen da. Innerhalb dieser müssen Variablen nicht mit Dollar markiert werden.
Ein Doppelpunkt hinter der schließenden Eckigen hilft auch nicht.
Ich weiß auch nicht, wo Du auf den Doppelpunkt gestoßen bist. Hier wahrscheinlich:
./backup-vm.sh: 33: [: missing ]
Da sind ja auch nur 3. ☺
Das heißt "in der Datei backup-vm.sh", "in Zeile 33", "[" sagt: "missing ]". Eine eckige Klammer zu ist aber da, also war vorher was, dass dem Interpreter gesagt hat, dass hier Schluss ist. Vielleicht sind && in [ ] unzulässig, und stattdessen muss man AND oder --and benutzen oder ähnlichen Kokolores. ☺
Ich denke, ich muss erst ein bisschen lesen... ☹ ... ist ja doch so ganz anders als C/C++, JAVA, C#...
|
Emma2
(Themenstarter)
Anmeldungsdatum: 28. Dezember 2018
Beiträge: 438
|
user_unknown schrieb: Emma2 schrieb:
Ja, die Bash ist schon furchtbar. Wenn sie nicht so praktisch wäre ...
Findich gar nicht furchtbar, nur recht ungewohnt für mich, der sonst eher in anderen Sprachen unterwegs ist. user_unknown schrieb: Allerdings will mir nicht in den Kopf, wieso Du mit Gewalt eine while-Loop benutzen willst, und arithmetische Ausdrücke in den Backsteinklammern.
Ganz einfach: Eine for-schleife ist "eigentlich" für eine vorher bekannte Anzahl von Durchläufen, und Deine for-Schleife ist semantisch eher ein while. (Sollte nicht arrogant klingen, sorry.) Aber das ist ja Wurscht, es muss doch mit while auch gehen. user_unknown schrieb: Ja, die Bash hat 4 Konstrukte für Bedingungen, [, [[, (( und ohne.
Dss muss ich wohl erstmal lesen: diese Klammerungen und die Dollars... user_unknown schrieb: Vielleicht sind && in [ ] unzulässig, und stattdessen muss man AND oder --and benutzen oder ähnlichen Kokolores. ☺
Puh, also doch erst lesen. BTW: Warum gibt es diese Inkonsistenzen (zumindest sehen die für mich - noch - so aus)? Sind das historische Relikte?
|
Emma2
(Themenstarter)
Anmeldungsdatum: 28. Dezember 2018
Beiträge: 438
|
Guten Morgen! Kurzes Update: Du hast Recht, dass && wohl innerhalb einer eckigen Klammer nicht erlaubt ist, es muss also sein
| while [ $stopped -eq 0 -a $steps -gt 0 ]
|
oder vermutlich
| while [ $stopped -eq 0 ] && [ $steps -gt 0 ]
|
, und der Grund hierfür ist tatsächlich die Historie und die Möglichkeiten verschiedener Shells. Ich mache also erst einmal ein paar Syntax-Experimente... und stoße schon wieder auf Widerstand. ☹
... da plötzlich fällt mir auf, dass meine erste Zeile
ja auch irgendwie blöd ist... denn
scheint mir deutlich erfolgreicher... 🙄 (habe ich aber bisher nicht mit gepostet, sonst wäre Euch das vermutlich aufgefallen)
|
user_unknown
Anmeldungsdatum: 10. August 2005
Beiträge: 17552
Wohnort: Berlin
|
Emma2 schrieb: user_unknown schrieb: Emma2 schrieb:
Ja, die Bash ist schon furchtbar. Wenn sie nicht so praktisch wäre ...
Findich gar nicht furchtbar, nur recht ungewohnt für mich, der sonst eher in anderen Sprachen unterwegs ist.
Keine Typsicherheit, globale Variable, ein halb Dutzend Weisen, ein If zu schreiben…
user_unknown schrieb: Allerdings will mir nicht in den Kopf, wieso Du mit Gewalt eine while-Loop benutzen willst, und arithmetische Ausdrücke in den Backsteinklammern.
Ganz einfach: Eine for-schleife ist "eigentlich" für eine vorher bekannte Anzahl von Durchläufen, und Deine for-Schleife ist semantisch eher ein while. (Sollte nicht arrogant klingen, sorry.) Aber das ist ja Wurscht, es muss doch mit while auch gehen.
Dass die Anzahl vorher bekannt sein muss ist nicht zwingend, aber das ist ja hier doch der Fall. Ob Du nun 60x 1s wartest oder 180x eine Drittel. Es klingt nicht arrogant, sondern falsch. Außerdem bietet sie eine Syntax zum Initialisieren frischer Variablen - genau, was Du brauchst, und zum Inkrementieren des Zählers, ebenfalls was Du brauchst. Hatte ich zuletzt schon geschrieben.
BTW: Warum gibt es diese Inkonsistenzen (zumindest sehen die für mich - noch - so aus)? Sind das historische Relikte?
Bin ich überfragt, aber ich vermute ja. Sporadisch habe ich mal was aufgeschnappt von Kompatibilität zu Vorläufern und dann gibt es wohl einen Spagat zwischen POSIX-konform und neuen Features, die man gerne hätte.
|
Emma2
(Themenstarter)
Anmeldungsdatum: 28. Dezember 2018
Beiträge: 438
|
user_unknown schrieb: Dass die Anzahl vorher bekannt sein muss ist nicht zwingend, aber das ist ja hier doch der Fall.
Nö, die Anzahl ist eben nicht bekannt: ich will ja nicht 60 Durchläufe warten, sondern nur so lange, bis meine Bedingung "VM down" erfüllt ist (die 60 ist ja nur das hineingefricketlet Pseudo-Timeout). Es ist also eine klassische while-Schleife, streng genommen sogar repeat-until. Damit kenne ich mich ein bisschen aus 😛. Aber, wie gesagt, trotz unterschiedlicher Syntax ist mit allen dreien die gleiche Semantik zu erreichen. Was den Rest abgeht: ja, es ist wohl die bash und Kompatibilität zu den anderen Shells, insbesondere sh, die so viele Möglichkeiten zu erlauben zwingt... 🙄 Ansonsten bin ich gleich mal mit einem Test durch und werde - falls's interessiert - die lauffähige Version hier posten. Danke für die vielen Anregungen und richtigen Richtungen!
|
user_unknown
Anmeldungsdatum: 10. August 2005
Beiträge: 17552
Wohnort: Berlin
|
Emma2 schrieb: user_unknown schrieb: Dass die Anzahl vorher bekannt sein muss ist nicht zwingend, aber das ist ja hier doch der Fall.
Nö, die Anzahl ist eben nicht bekannt: ich will ja nicht 60 Durchläufe warten, sondern nur so lange, bis meine Bedingung "VM down" erfüllt ist (die 60 ist ja nur das hineingefricketlet Pseudo-Timeout). Es ist also eine klassische while-Schleife, streng genommen sogar repeat-until. Damit kenne ich mich ein bisschen aus 😛. Aber, wie gesagt, trotz unterschiedlicher Syntax ist mit allen dreien die gleiche Semantik zu erreichen.
Du kannst der while-Schleife 2 Bedingungen nennen und der for-Schleife, und eine Bedingung ist es, maximal 60 Sekunden zu warten und den Zähler dafür müsstest Du bei der while-Schleife vor die Schleife ziehen und brauchst außerdem eine Extrazeile, um den Zähler hochzuzählen. Das bietet die Forschleife von Hause aus an und ist daher die passende Syntaxstruktur, auch wenn Du das mit einer Whileschleife auf schlechte Weise nachbauen kannst. Schlecht, weil die vorgezogenen Variablendeklarationen den Namensraum vermüllen. Das ist in C, C++ und Java auch schlechter Stil. Jetzt rumzueiern, dass Du nicht 60s warten willst, sondern nur, bis die VM runtergefahren ist, wenn das früher der Fall ist - dafür benutzt man ja die kombinierte Bedingung der for-Schleife, ist also ein Argument, das ins Leere greift. Um Arithmetik wie --steps zu machen, brauchst Du doppelte, runde Klammern. | x=10; for i in {1..5}; do ((--x)); done ; echo $x
|
|
Emma2
(Themenstarter)
Anmeldungsdatum: 28. Dezember 2018
Beiträge: 438
|
user_unknown schrieb: Das ist in C, C++ und Java auch schlechter Stil.
Falsch, aber darüber möchte ich mich echt nicht streiten.
|
user_unknown
Anmeldungsdatum: 10. August 2005
Beiträge: 17552
Wohnort: Berlin
|
Emma2 schrieb: user_unknown schrieb: Das ist in C, C++ und Java auch schlechter Stil.
Falsch, aber darüber möchte ich mich echt nicht streiten.
Dann reagierst Du am besten gar nicht drauf. ☺ So, als ob Du keine Argumente hättest. 😉
|