Einführung
Beim Schreiben von Skripten müssen Sie steuern, wie auf Daten zugegriffen wird und wie Funktionen den Erfolg oder Misserfolg einer Operation mitteilen.
Wenn Sie an zwei verschiedenen Stellen denselben Variablennamen verwenden, kann eine Variable die andere versehentlich überschreiben. Das ist ein häufiger Programmierfehler. Wir verhindern ihn mit Gültigkeitsbereichen (Variablen bleiben auf eine Funktion beschränkt).
Außerdem benötigen Funktionen eine Möglichkeit, dem Hauptskript mitzuteilen, ob sie erfolgreich waren oder fehlgeschlagen sind. In Bash geschieht das über Rückgabestatuscodes.
Dieses Thema verbindet zwei wichtige Konzepte für größere Skripte: Variablen dürfen nicht in Bereiche gelangen, in denen sie keine Auswirkungen haben sollen, und Erfolgs- oder Fehlerstatus steuern den Ausführungsablauf.
In diesem Lab lernen Sie:
- Variablen-Sichtbarkeit: Mit
localverhindern Sie Konflikte zwischen Variablen. - Rückgabestatus: Mit Exit-Codes (0 für Erfolg, ungleich null für Fehler) steuern Sie den Ablauf eines Skripts.
Variablen-Sichtbarkeit: Global und lokal
Standardmäßig sind Variablen in Bash global. Das bedeutet: Wenn Sie eine Variable innerhalb einer Funktion definieren, kann sie überall im Skript gelesen und geändert werden. Dadurch können schwer auffindbare Fehler entstehen, wenn ein Teil des Skripts versehentlich Daten ändert, die ein anderer Teil benötigt.
Um das zu verhindern, verwenden Sie das Schlüsselwort local. Eine local-Variable existiert nur innerhalb der Funktion, in der sie erstellt wurde.
Das ist ein typischer Zielkonflikt bei Shell-Skripten. Bash ermöglicht einen schnellen Einstieg, aber diese Bequemlichkeit kann auch dazu führen, dass Daten unerwartet im gesamten Skript sichtbar sind. Der Gültigkeitsbereich legt fest, an welchen Stellen eine Variable sichtbar ist.
Sehen wir uns den Unterschied an.
Erstellen Sie ein Skript mit dem Namen scope.sh:
cd ~/project
nano scope.sh
Fügen Sie den folgenden Code ein:
#!/bin/bash
## This is a Global variable
city="New York"
print_city() {
## This is a Local variable. It shares the name 'city', but it is a separate variable.
local city="London"
echo "Inside function: $city"
}
echo "Before function call: $city"
## Run the function
print_city
## Check if the Global variable was changed
echo "After function call: $city"
Speichern Sie die Datei mit Ctrl+O und bestätigen Sie mit Enter. Beenden Sie nano anschließend mit Ctrl+X.
Machen Sie das Skript ausführbar und führen Sie es aus:
chmod +x scope.sh
./scope.sh
Das Ergebnis:
Before function call: New York
Inside function: London
After function call: New York
Beachten Sie, dass die Variable city außerhalb der Funktion weiterhin den Wert „New York“ enthält. Die Funktion verwendet ihre eigene lokale Kopie von city mit dem Wert „London“ und ändert die globale Variable nicht.
Wenn wir local nicht verwendet hätten, hätte die Funktion die globale Variable überschrieben. Die letzte Zeile hätte dann „London“ ausgegeben.
Deshalb wird local wichtiger, je größer Skripte werden. In einem kurzen Beispiel wirken globale Variablen möglicherweise unproblematisch. In einem umfangreicheren Wartungsskript kann ein wiederverwendeter Variablenname jedoch schwer erkennbare Fehler verursachen.
Rückgabestatuscodes
In vielen Programmiersprachen geben Funktionen Daten zurück, zum Beispiel eine Zeichenkette oder eine Zahl. In Bash wird return ausschließlich für Statuscodes verwendet, die Erfolg oder Fehler anzeigen.
- 0: Erfolg.
- 1–255: Fehler.
Verwechseln Sie return nicht mit echo.
echogibt Text auf dem Bildschirm aus oder schreibt ihn in eine Variable, wenn die Ausgabe erfasst wird.returnübergibt eine unsichtbare Zahl an das System, um mitzuteilen: „Die Funktion war erfolgreich“ oder „Die Funktion ist fehlgeschlagen“.
Diese Unterscheidung ist grundlegend für die Shell-Programmierung. Eine Funktion kann mit echo lesbare Informationen ausgeben. Ihr return-Wert dient jedoch der Steuerung des Ablaufs und nicht der Übertragung beliebiger Daten.
Erstellen wir eine Funktion, die einen Fehler simuliert, indem sie den Code 5 zurückgibt.
Erstellen Sie status.sh:
nano ~/project/status.sh
Fügen Sie den folgenden Code ein:
#!/bin/bash
check_file() {
echo "Checking for file..."
## We simulate a specific error by returning Code 5
return 5
}
check_file
Speichern Sie die Datei und beenden Sie nano.
Machen Sie das Skript ausführbar und führen Sie es aus:
chmod +x status.sh
./status.sh
Ausgabe:
Checking for file...
Sie sehen den Text, aber wo ist die Zahl 5? Die Funktion hat sie still zurückgegeben. Im nächsten Schritt lernen Sie, wie Sie diesen Wert erfassen und verwenden.
Rückgabecode erfassen ($?)
Um den Rückgabecode des zuletzt ausgeführten Befehls oder der zuletzt ausgeführten Funktion abzurufen, stellt Bash die spezielle Variable $? bereit.
Nach der vollständigen Ausführung von check_file enthält $? automatisch den Wert 5.
Wichtige Regel: Sie müssen $? sofort nach der Ausführung des Befehls auslesen. Sobald Sie einen weiteren Befehl ausführen, auch ein einfaches echo, wird $? mit dem Status dieses neuen Befehls aktualisiert.
Ändern Sie status.sh, um den Code zu erfassen.
Öffnen Sie die Datei:
nano status.sh
Ersetzen Sie den Inhalt durch:
#!/bin/bash
check_file() {
echo "Checking for file..."
return 5
}
check_file
## Capture the return code immediately into a variable
ret_val=$?
echo "The function returned: $ret_val"
Speichern Sie die Datei und beenden Sie nano. Führen Sie das Skript erneut aus:
./status.sh
Ausgabe:
Checking for file...
The function returned: 5
Jetzt haben wir den Fehlercode in der Variable ret_val gespeichert.
Wenn Sie den Rückgabecode erfassen, kann der restliche Teil des Skripts sinnvoll darauf reagieren. Eine spätere if-Anweisung kann den Wert prüfen und entscheiden, ob das Skript fortgesetzt, ein Vorgang wiederholt oder das Skript beendet werden soll. So können Funktionen in größeren Skripten zusammenarbeiten, anstatt isolierte Codeabschnitte zu bleiben.
Auf den Rückgabestatus reagieren
Da uns der Statuscode nun vorliegt, können wir mit einer if-Anweisung Fehler kontrolliert behandeln.
- Bei Code
0ist alles in Ordnung. - Bei Code
5wissen wir genau, was schiefgelaufen ist, zum Beispiel: „Datei fehlt“.
So verhalten sich auch standardmäßige Linux-Befehle. grep gibt beispielsweise 0 zurück, wenn es eine Übereinstimmung findet, und 1, wenn es keine findet.
Erweitern Sie status.sh um die entsprechende Logik:
nano status.sh
Fügen Sie die bedingte Logik ein:
#!/bin/bash
check_file() {
echo "Checking for file..."
return 5
}
check_file
ret_val=$?
## Logic based on the return code
if [ $ret_val -eq 0 ]; then
echo "Success: File found."
elif [ $ret_val -eq 5 ]; then
echo "Error: File missing (Code 5)."
else
echo "Unknown Error: Code $ret_val"
fi
Speichern Sie die Datei und beenden Sie nano. Führen Sie das Skript aus:
./status.sh
Ausgabe:
Checking for file...
Error: File missing (Code 5).
Sie haben nun eine grundlegende Fehlerbehandlung implementiert. Wenn die Dateiprüfung fehlschlägt, erkennt Ihr Skript den Fehler und kann eine passende Fehlermeldung ausgeben, anstatt abzustürzen oder blind fortzufahren.
Zusammenfassung
In diesem Lab haben Sie zwei wichtige Konzepte der Skripterstellung geübt:
- Variablen-Sichtbarkeit (
local): Mitlocalverhindern Sie, dass Variablen innerhalb von Funktionen globale Variablen überschreiben. Dadurch bleibt das Verhalten Ihres Skripts vorhersehbar. - Rückgabestatus (
return,$?): Mit Exit-Codes können Funktionen dem Hauptskript Erfolg oder Fehler mitteilen. So können Sie Skripte schreiben, die intelligent auf Fehler reagieren.
Verwenden Sie für Variablen innerhalb von Funktionen grundsätzlich local, außer Sie müssen ausdrücklich eine globale Variable ändern.



