Ich schreibe ein Shell-Skript und muss überprüfen, ob eine Terminal-App installiert wurde. Ich möchte dazu einen TRY / CATCH-Befehl verwenden, es sei denn, es gibt einen saubereren Weg.
bash
shell
error-handling
Lee Probert
quelle
quelle
help test
Ihnen helfen könnte, die Lösung für Ihr Problem zu finden.trap
Befehl abfangen .Antworten:
Nein.
Bash hat nicht so viel Luxus, wie man in vielen Programmiersprachen finden kann.
Es gibt kein
try/catch
Bash; Mit&&
oder kann man jedoch ein ähnliches Verhalten erzielen||
.Verwenden von
||
:Wenn dies
command1
fehlschlägt, wirdcommand2
wie folgt ausgeführtIn ähnlicher Weise wird using ausgeführt
&&
,command2
wenn diescommand1
erfolgreich istDie nächste Annäherung von
try/catch
ist wie folgtBash enthält auch einige Fehlerbehandlungsmechanismen
Es stoppt Ihr Skript, wenn ein einfacher Befehl fehlschlägt.
Und warum auch nicht
if...else
. Es ist dein bester Freund.quelle
#save your output
nicht fehlschlägt, da sonst der Block "catch" weiterhin ausgeführt wird.if...else
Konstrukt zu verwenden. Bedeutet dies, dass Bash-Befehle als "wahr" aufgelöst werden, wenn sie erfolgreich ausgeführt werden, und als "falsch", wenn sie fehlschlagen?set -e
nicht unbedingt der beste Weg zu sein, Dinge zu tun. Hier sind einige Gegenargumente / Sonderfälle: mywiki.wooledge.org/BashFAQ/105Basierend auf einigen Antworten, die ich hier gefunden habe, habe ich mir eine kleine Hilfedatei für meine Projekte erstellt:
trycatch.sh
Hier ist ein Beispiel, wie es im Gebrauch aussieht:
quelle
||
nach demcatch
und vor dem{}
Block? Ich hätte gedacht, es wäre ein&&
if False or run_if_failed()
dass der Kurzschluss ODER die erste Anweisung ausprobiert hat, die nicht true zurückgegeben hat, und nun zur nächsten Anweisung übergeht.&&
würde nicht funktionieren, da die erste Anweisung (try
) false ergab, was bedeutet, dass diecatch
Anweisung nach der Tautologieregel nicht erforderlich istfalse&any equals false
. Nur ein nicht kurzgeschlossenes UND / ODER würde beides ausführen.Ich habe eine nahezu fehlerfreie Try & Catch-Implementierung in Bash entwickelt, mit der Sie Code schreiben können wie:
Sie können die Try-Catch-Blöcke sogar in sich selbst verschachteln!
Der Code ist Teil meines Bash Boilerplate / Frameworks . Es erweitert die Idee von Try & Catch weiter um Dinge wie Fehlerbehandlung mit Backtrace und Ausnahmen (plus einige andere nette Funktionen).
Hier ist der Code, der nur für try & catch verantwortlich ist:
Fühlen Sie sich frei zu verwenden, zu teilen und beizutragen - es ist auf GitHub .
quelle
my_output=$(try { code...; } catch { code...; })
Sie können verwenden
trap
:try { block A } catch { block B } finally { block C }
wird übersetzt in:
quelle
-E
Flagge, denke ich, so dass sich die Falle zu Funktionen ausbreitetEs gibt so viele ähnliche Lösungen, die wahrscheinlich funktionieren. Im Folgenden finden Sie eine einfache und funktionierende Methode zum Ausführen von Versuchen / Fangen mit Erläuterungen in den Kommentaren.
quelle
bash
bricht die laufende Ausführung nicht ab, falls etwas einen Fehlerstatus erkennt (es sei denn, Sie setzen das-e
Flag). Programmiersprachen, die dies anbieten,try/catch
tun dies, um ein "Bail-out" aufgrund dieser besonderen Situation zu verhindern (daher typischerweise als "Ausnahme" bezeichnet).In der
bash
wird verlassen stattdessen nur der Befehl in Frage mit einem Exit - Code größer als 0, was darauf hindeutet , dass der Fehlerzustand. Sie können das natürlich überprüfen, aber da es keine automatische Rettung gibt, ist ein Versuch / Fang nicht sinnvoll. Es fehlt nur dieser Kontext.Sie können jedoch eine Rettung simulieren , indem Sie Unterschalen verwenden, die an einem von Ihnen festgelegten Punkt enden können:
Stattdessen können Sie
some_condition
mit einemif
auch einfach einen Befehl ausprobieren. Falls er fehlschlägt (mit einem Exit-Code größer als 0), können Sie Folgendes retten:Leider sind Sie mit dieser Technik auf 255 verschiedene Exit-Codes (1..255) beschränkt, und es können keine anständigen Ausnahmeobjekte verwendet werden.
Wenn Sie weitere Informationen benötigen, um Ihre simulierte Ausnahme weiterzugeben, können Sie die Standardausgabe der Unterschalen verwenden, aber das ist etwas kompliziert und möglicherweise eine andere Frage ;-)
Mit dem oben genannten
-e
Flag für die Shell können Sie sogar diese expliziteexit
Anweisung entfernen:quelle
Wie jeder sagt, hat bash keine richtige sprachgestützte Try / Catch-Syntax. Sie können bash mit dem
-e
Argument starten oderset -e
im Skript verwenden, um den gesamten bash-Prozess abzubrechen, wenn ein Befehl einen Exit-Code ungleich Null enthält. (Sie können auchset +e
vorübergehend fehlgeschlagene Befehle zulassen.)Eine Technik zum Simulieren eines Try / Catch-Blocks besteht darin, einen Unterprozess zu starten, um die Arbeit mit
-e
aktiviertem zu erledigen . Überprüfen Sie dann im Hauptprozess den Rückkehrcode des Unterprozesses.Bash unterstützt Heredoc-Zeichenfolgen, sodass Sie nicht zwei separate Dateien schreiben müssen, um dies zu handhaben. Im folgenden Beispiel wird der TRY-Heredoc in einer separaten Bash-Instanz mit
-e
aktiviertem Befehl ausgeführt, sodass der Unterprozess abstürzt, wenn ein Befehl einen Exit-Code ungleich Null zurückgibt. Zurück im Hauptprozess können wir dann den Rückkehrcode überprüfen, um einen catch-Block zu behandeln.Es ist kein richtiger sprachunterstützter Try / Catch-Block, aber es kann einen ähnlichen Juckreiz für Sie verursachen.
quelle
Du kannst tun:
quelle
Und Sie haben Fallen http://www.tldp.org/LDP/Bash-Beginners-Guide/html/sect_12_02.html, die nicht dieselbe sind, aber andere Techniken, die Sie für diesen Zweck verwenden können
quelle
Eine sehr einfache Sache, die ich benutze:
quelle
||
befindet()
, wird sie in einer Unterschale ausgeführt und beendet, ohne dass die Hauptschale beendet wird. Verwenden Sie{ }
stattdessen die Gruppierung.Unten finden Sie eine vollständige Kopie des vereinfachten Skripts, das in meiner anderen Antwort verwendet wurde . Neben der zusätzlichen Fehlerprüfung gibt es einen Alias, mit dem der Benutzer den Namen eines vorhandenen Alias ändern kann. Die Syntax ist unten angegeben. Wenn der
new_alias
Parameter weggelassen wird, wird der Alias entfernt.Das vollständige Skript finden Sie unten.
quelle
Unten finden Sie ein Beispiel für ein Skript, das
try/catch/finally
in bash implementiert wird .Die Beispielskripte beginnen mit der Erstellung eines anonymen Fifos, mit dem Zeichenfolgennachrichten von einem
command exception
oderthrow
zum Ende des nächstentry
Blocks übergeben werden. Hier werden die Nachrichten aus dem FIFO entfernt und in eine Array-Variable eingefügt. Der Status wird überreturn
undexit
Befehle zurückgegeben und in eine andere Variable gestellt. Um einencatch
Block einzugeben , darf dieser Status nicht Null sein. Andere Anforderungen zur Eingabe einescatch
Blocks werden als Parameter übergeben. Wenn das Ende einescatch
Blocks erreicht ist, wird der Status auf Null gesetzt. Wenn das Ende desfinally
Blocks erreicht ist und der Status immer noch ungleich Null ist, wird ein impliziter Wurf ausgeführt, der die Nachrichten und den Status enthält. Das Skript erfordert den Aufruf der Funktion,trycatchfinally
die einen nicht behandelten Ausnahmebehandler enthält.Die Syntax für den
trycatchfinally
Befehl ist unten angegeben.Die
-c
Option fügt den Aufrufstapel zu den Ausnahmemeldungen hinzu.Die
-d
Option aktiviert die Debug-Ausgabe.Die
-e
Option aktiviert Befehlsausnahmen.Mit dieser
-h
Option kann der Benutzer seinen eigenen Befehlsausnahmehandler ersetzen.Die
-k
Option fügt den Aufrufstapel der Debug-Ausgabe hinzu.Die
-o
Option ersetzt die Standardausgabedatei/dev/fd/2
.Mit dieser
-u
Option kann der Benutzer seinen eigenen nicht behandelten Ausnahmebehandler ersetzen.Mit dieser
-v
Option kann der Benutzer Werte mithilfe der Befehlssubstitution zurückgeben.Das
fifo
ist der Fifo-Dateiname.Die Funktion
function
wird vontrycatchfinally
als Unterprozess aufgerufen .Die Syntax für den
catch
Befehl ist unten angegeben.Die Optionen sind unten definiert. Der Wert für die erste Liste ist der Status. Nachfolgende Werte sind die Nachrichten. Wenn mehr Nachrichten als Listen vorhanden sind, werden die verbleibenden Nachrichten ignoriert.
-e
bedeutet[[ $value == "$string" ]]
(der Wert muss mit mindestens einer Zeichenfolge in der Liste übereinstimmen)-n
bedeutet[[ $value != "$string" ]]
(der Wert kann mit keiner der Zeichenfolgen in der Liste übereinstimmen )-o
bedeutet[[ $value != $pattern ]]
(der Wert kann mit keinem der Muster in der Liste übereinstimmen)-p
bedeutet[[ $value == $pattern ]]
(der Wert hat mit mindestens einem Muster in der Liste übereinstimmen)-r
bedeutet[[ $value =~ $regex ]]
(der Wert muss mit mindestens einem erweiterten regulären Ausdruck in der Liste übereinstimmen )-t
bedeutet[[ ! $value =~ $regex ]]
(der Wert kann mit keinem der erweiterten regulären Ausdrücke in der Liste übereinstimmen)Das
try/catch/finally
Skript ist unten angegeben. Um das Skript für diese Antwort zu vereinfachen, wurde der größte Teil der Fehlerprüfung entfernt. Dies reduzierte die Größe um 64%. Eine vollständige Kopie dieses Skripts finden Sie unter meiner anderen Antwort .Unten sehen Sie ein Beispiel, bei dem davon ausgegangen wird, dass das obige Skript in der genannten Datei gespeichert ist
simple
. Diemakefifo
Datei enthält das in dieser Antwort beschriebene Skript . Es wird davon ausgegangen, dass die genannte Datei4444kkkkk
nicht vorhanden ist und daher eine Ausnahme auftritt. Die vomls 4444kkkkk
Befehl ausgegebene Fehlermeldung wird automatisch unterdrückt, bis sie sich im entsprechendencatch
Block befindet.Das obige Skript wurde mit getestet
GNU bash, version 3.2.57(1)-release (x86_64-apple-darwin17)
. Die Ausgabe beim Ausführen dieses Skripts ist unten dargestellt.Ein weiteres Beispiel, das a verwendet,
throw
kann erstellt werden, indem die FunktionMyFunction3
durch das unten gezeigte Skript ersetzt wird.Die Syntax für den
throw
Befehl ist unten angegeben. Wenn keine Parameter vorhanden sind, werden stattdessen Status und Nachrichten verwendet, die in den Variablen gespeichert sind.Die Ausgabe der Ausführung des geänderten Skripts ist unten dargestellt.
quelle