Nein, es gibt keine gotoBash (zumindest steht es command not foundfür mich). Warum? Wahrscheinlich gibt es einen besseren Weg, dies zu tun.
Niklas B.
153
Er kann seine Gründe haben. Ich habe diese Frage gefunden, weil ich möchte, dass eine gotoAnweisung viel Code zum Debuggen eines großen Skripts überspringt, ohne eine Stunde auf die Ausführung verschiedener nicht zusammenhängender Aufgaben zu warten. Ich würde gotoim Produktionscode sicherlich kein a verwenden , aber zum Debuggen meines Codes würde dies mein Leben unendlich erleichtern und es wäre leichter zu erkennen, wenn es darum geht, ihn zu entfernen.
Karl Nicoll
30
@delnan Aber kein goto zu haben kann einige Dinge komplizierter machen. Es gibt tatsächlich Anwendungsfälle.
glglgl
70
Ich habe diesen Mythos satt! Es ist nichts falsch mit goto! Alles, was Sie schreiben, wird schließlich gehe. Im Assembler gibt es nur goto. Ein guter Grund, goto in höheren Programmiersprachen zu verwenden, ist beispielsweise das saubere und lesbare Herausspringen aus verschachtelten Schleifen.
Alexander Czutro
25
"Avo goto" ist eine gute Regel. Wie jede Regel sollte es in drei Phasen gelernt werden. Erstens: Befolgen Sie die Regel, bis es zur zweiten Natur geworden ist. Zweitens lernen Sie, die Gründe für die Regel zu verstehen. Drittens lernen Sie gute Ausnahmen von der Regel, basierend auf einem umfassenden Verständnis der Einhaltung der Regel und der Gründe für die Regel. Vermeiden Sie es, die obigen Schritte zu überspringen, da dies mit "goto" vergleichbar wäre. ;-)
Jeff Learman
Antworten:
75
Nein, da ist kein; siehe §3.2.4 „Compound - Befehle“ in dem Bash - Referenzhandbuch für Informationen über die Kontrollstrukturen , die tun exist. Beachten Sie insbesondere die Erwähnung von breakund continue, die nicht so flexibel sind wie goto, aber in Bash flexibler sind als in einigen Sprachen, und Ihnen möglicherweise dabei helfen, das zu erreichen, was Sie wollen. (Was auch immer du willst ...)
Könnten Sie "flexibler in Bash als in einigen Sprachen" erweitern?
user239558
21
@ user239558: In einigen Sprachen können Sie nur zur breakoder continuevon der innersten Schleife gelangen, während Sie in Bash angeben können, wie viele Ebenen der Schleife übersprungen werden sollen. (Und selbst bei Sprachen, die es Ihnen ermöglichen, zu breakoder continuevon beliebigen Schleifen zu gelangen, erfordern die meisten, dass diese statisch ausgedrückt werden - z. B. break foo;aus der mit Schleife gekennzeichneten Schleife ausbrechen foo-, während sie in Bash dynamisch ausgedrückt werden - z. B. break "$foo"aus $fooSchleifen ausbrechen . )
Ruakh
Ich würde empfehlen, Funktionen mit den erforderlichen Funktionen zu definieren und sie aus anderen Teilen des Codes zu kalibrieren.
Blmayer
123
Wenn Sie damit einen Teil eines großen Skripts zum Debuggen überspringen (siehe Karl Nicolls Kommentar), könnte false eine gute Option sein (nicht sicher, ob "false" immer verfügbar ist, für mich in / bin / false) ::
# ... Code I want to run here ...if false;then# ... Code I want to skip here ...fi# ... I want to resume here ...
Die Schwierigkeit tritt auf, wenn es Zeit ist, Ihren Debugging-Code herauszureißen. Das "wenn falsch" -Konstrukt ist ziemlich einfach und einprägsam, aber wie finden Sie die passende Fi? Wenn Ihr Editor das Blockieren des Einrückens zulässt, können Sie den übersprungenen Block einrücken (dann möchten Sie ihn zurücksetzen, wenn Sie fertig sind). Oder ein Kommentar zur Fi-Zeile, aber es müsste etwas sein, an das Sie sich erinnern werden, von dem ich vermute, dass es sehr programmiererabhängig sein wird.
Ja falseist immer verfügbar. Wenn Sie jedoch einen Codeblock haben, den Sie nicht ausführen möchten, kommentieren Sie ihn einfach aus. Oder löschen Sie es (und schauen Sie in Ihrem Versionsverwaltungssystem nach, wenn Sie es später wiederherstellen müssen).
Keith Thompson
1
Wenn der Codeblock zu lang ist, um eine Zeile nach der anderen mühsam zu kommentieren, lesen Sie diese Tricks. stackoverflow.com/questions/947897/… Diese helfen jedoch keinem Texteditor, den Anfang mit dem Ende abzugleichen , sodass sie keine große Verbesserung darstellen.
Camille Goudeseune
4
"if false" ist oft weitaus besser als das Auskommentieren von Code, da dadurch sichergestellt wird, dass der beiliegende Code weiterhin ein gesetzlicher Code ist. Die beste Entschuldigung für das Auskommentieren von Code ist, wenn er wirklich gelöscht werden muss, aber es gibt etwas, an das man sich erinnern muss - es ist also nur ein Kommentar und kein "Code" mehr.
Jeff Learman
1
Ich benutze den Kommentar '#if false;'. Auf diese Weise kann ich einfach danach suchen und sowohl den Anfang als auch das Ende des Debug-Entfernungsabschnitts finden.
Jon
Diese Antwort sollte nicht positiv bewertet werden, da sie in keiner Weise auf die Frage des OP antwortet.
Viktor Joras
54
Es kann in der Tat für einige Debug- oder Demonstrationsanforderungen nützlich sein.
"Mein Bestreben, Bash wie Assemblersprache aussehen zu lassen, rückt immer näher." - Beeindruckend. Einfach wow.
Brian Agnew
5
Das einzige, was ich ändern würde, ist, es so zu gestalten, dass Beschriftungen so beginnen : start:, dass sie keine Syntaxfehler sind.
Alexej Magura
5
Wäre besser, wenn Sie das tun würden: cmd = $ (sed -n "/ # $ label: / {: a; n; p; ba};" $ 0 | grep -v ': $') mit Labels, die wie folgt beginnen: # Start: => Dies würde
Skriptfehler
2
Hm, in der Tat ist es höchstwahrscheinlich mein Fehler. Ich habe den Beitrag bearbeitet. Danke dir.
Hubbitus
2
set -xhilft zu verstehen, was los ist
John Lin
30
Sie können casein bash verwenden, um ein goto zu simulieren:
#!/bin/bashcase bar in
foo)
echo foo
;&
bar)
echo bar
;&*)
echo star
;;esac
Beachten Sie, dass dies erforderlich ist bash v4.0+. Es handelt sich jedoch nicht um eine allgemeine, gotosondern um eine Durchfalloption für die caseAnweisung.
mklement0
3
Ich denke, das sollte die Antwort sein. Ich habe ein echtes Bedürfnis zu gehen, um die Wiederaufnahme der Ausführung eines Skripts von einer gegebenen Anweisung zu unterstützen. Dies ist in jeder Hinsicht, aber Semantik, Goto, Semantik und syntaktischer Zucker sind niedlich, aber nicht unbedingt notwendig. tolle Lösung, IMO.
Nathan g
1
@nathang, ob es die Antwort ist, hängt davon ab, ob Ihr Fall mit der Teilmenge des allgemeinen Falls übereinstimmt, nach dem das OP gefragt hat. Leider fragt die Frage nach dem allgemeinen Fall, was diese Antwort zu eng macht, um richtig zu sein. (Ob diese Frage aus diesem Grund als zu weit gefasst geschlossen werden sollte , ist eine andere Diskussion).
Charles Duffy
1
goto ist mehr als nur auswählen. goto feature bedeutet, unter bestimmten Bedingungen zu Orten springen zu können und sogar einen schleifenartigen Fluss zu erzeugen ...
Sergio Abreu
19
Wenn Sie ein Bash-Skript testen / debuggen und einfach einen oder mehrere Codeabschnitte überspringen möchten, ist dies eine sehr einfache Methode, die auch später leicht zu finden und zu entfernen ist (im Gegensatz zu den meisten Methoden) oben beschrieben).
#!/bin/bash
echo "Run this"
cat >/dev/null <<GOTO_1
echo "Don't run this"
GOTO_1
echo "Also run this"
cat >/dev/null <<GOTO_2
echo "Don't run this either"
GOTO_2
echo "Yet more code I want to run"
Um Ihr Skript wieder normal zu machen, löschen Sie einfach alle Zeilen mit GOTO.
Wir können diese Lösung auch verschönern, indem wir einen gotoBefehl als Alias hinzufügen :
#!/bin/bash
shopt -s expand_aliases
alias goto="cat >/dev/null <<"
goto GOTO_1
echo "Don't run this"
GOTO_1
echo "Run this"
goto GOTO_2
echo "Don't run this either"
GOTO_2
echo "All done"
Aliase funktionieren normalerweise nicht in Bash-Skripten, daher benötigen wir den shoptBefehl, um dies zu beheben.
Wenn Sie Ihre aktivieren / deaktivieren möchten goto, benötigen wir ein bisschen mehr:
#!/bin/bash
shopt -s expand_aliases
if[-n "$DEBUG"];then
alias goto="cat >/dev/null <<"else
alias goto=":"fi
goto '#GOTO_1'
echo "Don't run this"#GOTO1
echo "Run this"
goto '#GOTO_2'
echo "Don't run this either"#GOTO_2
echo "All done"
Dann können Sie dies tun, export DEBUG=TRUEbevor Sie das Skript ausführen.
Die Beschriftungen sind Kommentare und verursachen daher keine Syntaxfehler, wenn Sie unsere goto's deaktivieren (indem Sie gotodas' :'no-op' setzen). Dies bedeutet jedoch, dass wir sie in unseren gotoAnweisungen zitieren müssen .
Wenn gotoSie eine Lösung verwenden, müssen Sie darauf achten, dass der Code, an dem Sie vorbeigehen, keine Variablen festlegt, auf die Sie sich später verlassen. Möglicherweise müssen Sie diese Definitionen an den Anfang Ihres Skripts oder direkt über eine verschieben Ihrer gotoAussagen.
Laurences Lösung ist einfach cool, ohne auf das Gute / Schlechte von goto einzugehen. Du hast meine Stimme bekommen.
Mogens TrasherDK
1
Das ist eher ein Sprung zu, if(false)scheint (für mich) sinnvoller zu sein.
Vesperto
2
Das Zitieren des goto "label" bedeutet auch, dass das here-doc nicht erweitert / ausgewertet wird, was Sie vor einigen schwer zu findenden Fehlern bewahrt (nicht zitiert, es würde unterliegen: Parametererweiterung, Befehlssubstitution und arithmetische Erweiterung, die alle haben können Nebenwirkungen). Sie können dies auch ein wenig optimieren alias goto=":<<"und ganz darauf verzichten cat.
mr.spuratic
Ja, Vesperto, Sie können eine 'if'-Anweisung verwenden, und das habe ich in vielen Skripten getan, aber es wird sehr chaotisch und ist viel schwieriger zu kontrollieren und zu verfolgen, insbesondere wenn Sie Ihre Sprungpunkte häufig ändern möchten.
Laurence Renshaw
12
Obwohl andere bereits klargestellt haben, dass es gotoin bash kein direktes Äquivalent gibt (und die nächstgelegenen Alternativen wie Funktionen, Schleifen und break bereitgestellt haben), möchte ich veranschaulichen, wie die Verwendung eines loop plus breakeine bestimmte Art von goto-Anweisung simulieren kann.
Die Situation, in der ich dies am nützlichsten finde, ist, wenn ich zum Anfang eines Codeabschnitts zurückkehren muss, wenn bestimmte Bedingungen nicht erfüllt sind. Im folgenden Beispiel wird die while-Schleife für immer ausgeführt, bis der Ping keine Pakete mehr an eine Test-IP sendet.
#!/bin/bashTestIP="8.8.8.8"# Loop forever (until break is issued)while true;do# Do a simple test for Internet connectivityPacketLoss=$(ping "$TestIP"-c 2| grep -Eo"[0-9]+% packet loss"| grep -Eo"^[0-9]")# Exit the loop if ping is no longer dropping packetsif["$PacketLoss"==0];then
echo "Connection restored"breakelse
echo "No connectivity"fidone
Entfernt wahllos alle Codezeilen, die mit a enden :
Behandelt label:irgendwo in einer Zeile als Etikett
Hier ist eine feste ( shell-checksaubere) Version:
#!/bin/bash# GOTO for bash, based upon https://stackoverflow.com/a/31269848/5353461function goto
{local label=$1
cmd=$(sed -En"/^[[:space:]]*#[[:space:]]*$label:[[:space:]]*#/{:a;n;p;ba};""$0")eval"$cmd"
exit
}
start=${1:-start}
goto "$start"# GOTO start: by default#start:# Comments can occur after labels
echo start
goto end
# skip: # Whitespace is allowed
echo this is usually skipped
# end: #
echo end
Es gibt noch eine weitere Möglichkeit, die gewünschten Ergebnisse zu erzielen: Befehl trap. Es kann zum Beispiel zu Reinigungszwecken verwendet werden.
Hier ist eine schmutzige Problemumgehung, mit trapder nur rückwärts gesprungen wird :)
#!/bin/bash -e
trap '
echo I am
sleep 1
echo here now.
' EXIT
echo foo
goto trap 2>/dev/null
echo bar
Ausgabe:
$ ./test.sh
foo
I am
here now.
Dies sollte nicht auf diese Weise verwendet werden, sondern nur zu Bildungszwecken. Hier ist, warum dies funktioniert:
trapverwendet die Ausnahmebehandlung, um die Änderung des Codeflusses zu erreichen. In diesem Fall trapfängt das alles ab, was dazu führt, dass das Skript beendet wird. Der Befehl gotoexistiert nicht und löst daher einen Fehler aus, der normalerweise das Skript beendet. Dieser Fehler wird abgefangen trapund 2>/dev/nullverbirgt die Fehlermeldung, die normalerweise angezeigt wird.
Diese Implementierung von goto ist offensichtlich nicht zuverlässig, da jeder nicht vorhandene Befehl (oder jeder andere Fehler auf diese Weise) denselben Trap-Befehl ausführen würde. Insbesondere können Sie nicht auswählen, zu welchem Etikett Sie wechseln möchten.
Grundsätzlich benötigen Sie im realen Szenario keine goto-Anweisungen, sie sind redundant, da zufällige Aufrufe an verschiedene Stellen Ihren Code nur schwer verständlich machen.
Wenn Ihr Code mehrmals aufgerufen wird, sollten Sie die Schleife verwenden und den Workflow ändern, um continueund zu verwenden break.
Wenn sich Ihr Code selbst wiederholt, sollten Sie die Funktion schreiben und so oft aufrufen, wie Sie möchten.
Wenn Ihr Code basierend auf dem Variablenwert in einen bestimmten Abschnitt springen muss, sollten Sie die Verwendung einer caseAnweisung in Betracht ziehen .
Wenn Sie Ihren langen Code in kleinere Teile aufteilen können, sollten Sie ihn in separate Dateien verschieben und über das übergeordnete Skript aufrufen.
Was ist der Unterschied zwischen dieser Form und einer normalen Funktion?
Yurenchen
2
@yurenchen - Stellen Sie sich vor trap, Sie verwenden exception handling, um die Änderung des Codeflusses zu erreichen. In diesem Fall fängt der Trap alles ab, was das Skript dazu veranlasst EXIT, was durch Aufrufen des nicht vorhandenen Befehls ausgelöst wird goto. Übrigens: Das Argument goto trapkann alles sein, goto ignoredda es das ist goto, was den EXIT verursacht, und das 2>/dev/nulldie Fehlermeldung verbirgt, dass Ihr Skript beendet wird.
Jesse Chisholm
2
Dies ist eine kleine Korrektur des von Hubbbitus erstellten Judy Schmidt-Skripts.
Das Einfügen von nicht maskierten Etiketten in das Skript war auf dem Computer problematisch und führte zum Absturz. Dies war leicht zu lösen, indem # hinzugefügt wurde, um den Beschriftungen zu entkommen. Vielen Dank an Alexej Magura und access_granted für ihre Vorschläge.
#!/bin/bash# include this boilerplatefunction goto {
label=$1
cmd=$(sed -n "/$#label#:/{:a;n;p;ba};" $0 | grep -v ':$')eval"$cmd"
exit
}
start=${1:-"start"}
goto $start
#start#
echo "start"
goto bing
#boom#
echo boom
goto eof
#bang#
echo bang
goto boom
#bing#
echo bing
goto bang
#eof#
echo "the end mother-hugger..."
Dieses Kopieren und Einfügen funktioniert nicht => Es ist noch ein Jumpto vorhanden.
Alexis Paques
Was bedeutet das? Was funktioniert nicht? Könnten Sie genauer sein?
Thebunnyrules
Natürlich habe ich den Code ausprobiert! Ich habe unter 5 oder 6 verschiedenen Bedingungen getestet, bevor ich alles erfolgreich gepostet habe. Wie ist der Code für Sie fehlgeschlagen, welche Fehlermeldung oder welcher Code?
Thebunnyrules
Was auch immer. Ich möchte Ihnen helfen, aber Sie sind wirklich vage und nicht kommunikativ (ganz zu schweigen von der Beleidigung mit der Frage "Haben Sie es getestet?"). Was bedeutet "Sie haben nicht richtig eingefügt"? Wenn Sie sich auf das "/ $ # label #: / {: a; n; p; ba};" Teil, ich bin mir sehr bewusst, dass es anders ist. Ich habe es für das neue Etikettenformat geändert (auch bekannt als # label # vs: label in einer anderen Antwort, bei der das Skript in einigen Fällen abstürzte). Haben Sie ein gültiges Problem mit meiner Antwort (wie Skriptabsturz oder schlechte Syntax) oder haben Sie einfach meine Antwort -1, weil Sie dachten "Ich weiß nicht, wie man ausschneidet und einfügt"?
Thebunnyrules
1
@thebunnyrules Ich bin auf dasselbe Problem gestoßen wie Sie, habe es aber anders gelöst +1 für Ihre Lösung!
Fabby
2
Eine einfache Suche zum Auskommentieren von Codeblöcken beim Debuggen.
GOTO=false
if ${GOTO};then
echo "GOTO failed"...fi# End of GOTO
echo "GOTO done"
Ich habe einen Weg gefunden, dies mithilfe von Funktionen zu tun.
Nehmen wir zum Beispiel, haben Sie 3 Möglichkeiten: A, B, und C. Aund Bführen Sie einen Befehl aus, erhalten CSie jedoch weitere Informationen und gelangen erneut zur ursprünglichen Eingabeaufforderung. Dies kann mit Funktionen erfolgen.
Beachten Sie, dass function demoFunctionSie demoFunctionnach diesem Skript aufrufen müssen , da die Zeile nur die Funktion einrichtet , damit die Funktion tatsächlich ausgeführt wird.
Sie können dies einfach anpassen, indem Sie mehrere andere Funktionen schreiben und aufrufen, wenn Sie eine GOTOandere Stelle in Ihrem Shell-Skript " " benötigen .
function demoFunction {
read -n1 -p "Pick a letter to run a command [A, B, or C for more info] " runCommand
case $runCommand in
a|A) printf "\n\tpwd being executed...\n"&& pwd;;
b|B) printf "\n\tls being executed...\n"&& ls;;
c|C) printf "\n\toption A runs pwd, option B runs ls\n"&& demoFunction;;esac}
demoFunction
goto
Bash (zumindest steht escommand not found
für mich). Warum? Wahrscheinlich gibt es einen besseren Weg, dies zu tun.goto
Anweisung viel Code zum Debuggen eines großen Skripts überspringt, ohne eine Stunde auf die Ausführung verschiedener nicht zusammenhängender Aufgaben zu warten. Ich würdegoto
im Produktionscode sicherlich kein a verwenden , aber zum Debuggen meines Codes würde dies mein Leben unendlich erleichtern und es wäre leichter zu erkennen, wenn es darum geht, ihn zu entfernen.Antworten:
Nein, da ist kein; siehe §3.2.4 „Compound - Befehle“ in dem Bash - Referenzhandbuch für Informationen über die Kontrollstrukturen , die tun exist. Beachten Sie insbesondere die Erwähnung von
break
undcontinue
, die nicht so flexibel sind wiegoto
, aber in Bash flexibler sind als in einigen Sprachen, und Ihnen möglicherweise dabei helfen, das zu erreichen, was Sie wollen. (Was auch immer du willst ...)quelle
break
odercontinue
von der innersten Schleife gelangen, während Sie in Bash angeben können, wie viele Ebenen der Schleife übersprungen werden sollen. (Und selbst bei Sprachen, die es Ihnen ermöglichen, zubreak
odercontinue
von beliebigen Schleifen zu gelangen, erfordern die meisten, dass diese statisch ausgedrückt werden - z. B.break foo;
aus der mit Schleife gekennzeichneten Schleife ausbrechenfoo
-, während sie in Bash dynamisch ausgedrückt werden - z. B.break "$foo"
aus$foo
Schleifen ausbrechen . )Wenn Sie damit einen Teil eines großen Skripts zum Debuggen überspringen (siehe Karl Nicolls Kommentar), könnte false eine gute Option sein (nicht sicher, ob "false" immer verfügbar ist, für mich in / bin / false) ::
Die Schwierigkeit tritt auf, wenn es Zeit ist, Ihren Debugging-Code herauszureißen. Das "wenn falsch" -Konstrukt ist ziemlich einfach und einprägsam, aber wie finden Sie die passende Fi? Wenn Ihr Editor das Blockieren des Einrückens zulässt, können Sie den übersprungenen Block einrücken (dann möchten Sie ihn zurücksetzen, wenn Sie fertig sind). Oder ein Kommentar zur Fi-Zeile, aber es müsste etwas sein, an das Sie sich erinnern werden, von dem ich vermute, dass es sehr programmiererabhängig sein wird.
quelle
false
ist immer verfügbar. Wenn Sie jedoch einen Codeblock haben, den Sie nicht ausführen möchten, kommentieren Sie ihn einfach aus. Oder löschen Sie es (und schauen Sie in Ihrem Versionsverwaltungssystem nach, wenn Sie es später wiederherstellen müssen).Es kann in der Tat für einige Debug- oder Demonstrationsanforderungen nützlich sein.
Ich fand die Bob Copeland-Lösung http://bobcopeland.com/blog/2012/10/goto-in-bash/ elegant:
Ergebnisse in:
quelle
: start:
, dass sie keine Syntaxfehler sind.set -x
hilft zu verstehen, was los istSie können
case
in bash verwenden, um ein goto zu simulieren:produziert:
quelle
bash v4.0+
. Es handelt sich jedoch nicht um eine allgemeine,goto
sondern um eine Durchfalloption für diecase
Anweisung.Wenn Sie ein Bash-Skript testen / debuggen und einfach einen oder mehrere Codeabschnitte überspringen möchten, ist dies eine sehr einfache Methode, die auch später leicht zu finden und zu entfernen ist (im Gegensatz zu den meisten Methoden) oben beschrieben).
Um Ihr Skript wieder normal zu machen, löschen Sie einfach alle Zeilen mit
GOTO
.Wir können diese Lösung auch verschönern, indem wir einen
goto
Befehl als Alias hinzufügen :Aliase funktionieren normalerweise nicht in Bash-Skripten, daher benötigen wir den
shopt
Befehl, um dies zu beheben.Wenn Sie Ihre aktivieren / deaktivieren möchten
goto
, benötigen wir ein bisschen mehr:Dann können Sie dies tun,
export DEBUG=TRUE
bevor Sie das Skript ausführen.Die Beschriftungen sind Kommentare und verursachen daher keine Syntaxfehler, wenn Sie unsere
goto
's deaktivieren (indem Siegoto
das':
'no-op' setzen). Dies bedeutet jedoch, dass wir sie in unserengoto
Anweisungen zitieren müssen .Wenn
goto
Sie eine Lösung verwenden, müssen Sie darauf achten, dass der Code, an dem Sie vorbeigehen, keine Variablen festlegt, auf die Sie sich später verlassen. Möglicherweise müssen Sie diese Definitionen an den Anfang Ihres Skripts oder direkt über eine verschieben Ihrergoto
Aussagen.quelle
if(false)
scheint (für mich) sinnvoller zu sein.alias goto=":<<"
und ganz darauf verzichtencat
.Obwohl andere bereits klargestellt haben, dass es
goto
in bash kein direktes Äquivalent gibt (und die nächstgelegenen Alternativen wie Funktionen, Schleifen und break bereitgestellt haben), möchte ich veranschaulichen, wie die Verwendung eines loop plusbreak
eine bestimmte Art von goto-Anweisung simulieren kann.Die Situation, in der ich dies am nützlichsten finde, ist, wenn ich zum Anfang eines Codeabschnitts zurückkehren muss, wenn bestimmte Bedingungen nicht erfüllt sind. Im folgenden Beispiel wird die while-Schleife für immer ausgeführt, bis der Ping keine Pakete mehr an eine Test-IP sendet.
quelle
Diese Lösung hatte die folgenden Probleme:
:
label:
irgendwo in einer Zeile als EtikettHier ist eine feste (
shell-check
saubere) Version:quelle
Es gibt noch eine weitere Möglichkeit, die gewünschten Ergebnisse zu erzielen: Befehl
trap
. Es kann zum Beispiel zu Reinigungszwecken verwendet werden.quelle
Es gibt keine
goto
in Bash.Hier ist eine schmutzige Problemumgehung, mit
trap
der nur rückwärts gesprungen wird :)Ausgabe:
Dies sollte nicht auf diese Weise verwendet werden, sondern nur zu Bildungszwecken. Hier ist, warum dies funktioniert:
trap
verwendet die Ausnahmebehandlung, um die Änderung des Codeflusses zu erreichen. In diesem Falltrap
fängt das alles ab, was dazu führt, dass das Skript beendet wird. Der Befehlgoto
existiert nicht und löst daher einen Fehler aus, der normalerweise das Skript beendet. Dieser Fehler wird abgefangentrap
und2>/dev/null
verbirgt die Fehlermeldung, die normalerweise angezeigt wird.Diese Implementierung von goto ist offensichtlich nicht zuverlässig, da jeder nicht vorhandene Befehl (oder jeder andere Fehler auf diese Weise) denselben Trap-Befehl ausführen würde. Insbesondere können Sie nicht auswählen, zu welchem Etikett Sie wechseln möchten.
Grundsätzlich benötigen Sie im realen Szenario keine goto-Anweisungen, sie sind redundant, da zufällige Aufrufe an verschiedene Stellen Ihren Code nur schwer verständlich machen.
Wenn Ihr Code mehrmals aufgerufen wird, sollten Sie die Schleife verwenden und den Workflow ändern, um
continue
und zu verwendenbreak
.Wenn sich Ihr Code selbst wiederholt, sollten Sie die Funktion schreiben und so oft aufrufen, wie Sie möchten.
Wenn Ihr Code basierend auf dem Variablenwert in einen bestimmten Abschnitt springen muss, sollten Sie die Verwendung einer
case
Anweisung in Betracht ziehen .Wenn Sie Ihren langen Code in kleinere Teile aufteilen können, sollten Sie ihn in separate Dateien verschieben und über das übergeordnete Skript aufrufen.
quelle
trap
, Sie verwendenexception handling
, um die Änderung des Codeflusses zu erreichen. In diesem Fall fängt der Trap alles ab, was das Skript dazu veranlasstEXIT
, was durch Aufrufen des nicht vorhandenen Befehls ausgelöst wirdgoto
. Übrigens: Das Argumentgoto trap
kann alles sein,goto ignored
da es das istgoto
, was den EXIT verursacht, und das2>/dev/null
die Fehlermeldung verbirgt, dass Ihr Skript beendet wird.Dies ist eine kleine Korrektur des von Hubbbitus erstellten Judy Schmidt-Skripts.
Das Einfügen von nicht maskierten Etiketten in das Skript war auf dem Computer problematisch und führte zum Absturz. Dies war leicht zu lösen, indem # hinzugefügt wurde, um den Beschriftungen zu entkommen. Vielen Dank an Alexej Magura und access_granted für ihre Vorschläge.
quelle
Eine einfache Suche zum Auskommentieren von Codeblöcken beim Debuggen.
Ergebnis ist-> GOTO erledigt
quelle
Ich habe einen Weg gefunden, dies mithilfe von Funktionen zu tun.
Nehmen wir zum Beispiel, haben Sie 3 Möglichkeiten:
A
,B
, undC
.A
undB
führen Sie einen Befehl aus, erhaltenC
Sie jedoch weitere Informationen und gelangen erneut zur ursprünglichen Eingabeaufforderung. Dies kann mit Funktionen erfolgen.Beachten Sie, dass
function demoFunction
SiedemoFunction
nach diesem Skript aufrufen müssen , da die Zeile nur die Funktion einrichtet , damit die Funktion tatsächlich ausgeführt wird.Sie können dies einfach anpassen, indem Sie mehrere andere Funktionen schreiben und aufrufen, wenn Sie eine
GOTO
andere Stelle in Ihrem Shell-Skript " " benötigen .quelle