Bash-Crashkurs: Skripting-Grundlagen: Unterschied zwischen den Versionen
| Zeile 1: | Zeile 1: | ||
| + | = Bash-Crashkurs: Skripting-Grundlagen = | ||
| + | |||
| + | Dieser Kurs vermittelt die Bash-Mechanismen, die für ein eigenes Skript zur Netzwerkkonfiguration gebraucht werden. Jeder Abschnitt führt einen Baustein ein. Am Ende schreibt ihr daraus selbst ein vollständiges Skript. | ||
| + | |||
| + | == Variablensubstitution == | ||
| + | |||
| + | Eine Variable wird ohne Leerzeichen um das <code>=</code> gesetzt: | ||
| + | |||
| + | <syntaxhighlight lang="bash"> | ||
| + | NAME="server01" | ||
| + | </syntaxhighlight> | ||
| + | |||
| + | Der Wert wird ausgelesen, indem man ein <code>$</code> vor den Namen setzt – dieser Vorgang heißt Variablensubstitution: Bash ersetzt <code>$NAME</code> durch den gespeicherten Wert, bevor der Befehl ausgeführt wird. | ||
| + | |||
| + | <syntaxhighlight lang="bash"> | ||
| + | echo $NAME | ||
| + | echo "$NAME" | ||
| + | </syntaxhighlight> | ||
| + | |||
| + | In Anführungszeichen referenzieren, sonst gibt's bei Leerzeichen oder Sonderzeichen im Wert Probleme (Bash zerlegt den Wert sonst an Leerzeichen in mehrere Wörter). | ||
| + | |||
| + | ;Übung | ||
| + | <pre> | ||
| + | Setzt eine Variable ADDR mit dem Wert 10.2XX.0.10/24 und gebt sie einmal ohne und einmal mit Anführungszeichen aus. | ||
| + | </pre> | ||
| + | |||
| + | == Kommandosubstitution == | ||
| + | |||
| + | Mit <code>$(...)</code> wird nicht der Text eines Befehls ausgeführt, sondern seine Ausgabe als Wert eingesetzt – das nennt man Kommandosubstitution: | ||
| + | |||
| + | <syntaxhighlight lang="bash"> | ||
| + | DATUM=$(date +%Y-%m-%d) | ||
| + | echo "$DATUM" | ||
| + | </syntaxhighlight> | ||
| + | |||
| + | <code>$(date +%Y-%m-%d)</code> wird zuerst ausgeführt, die Ausgabe des Befehls landet dann in <code>DATUM</code>. | ||
| + | |||
| + | ;Übung | ||
| + | <pre> | ||
| + | Speichert die Ausgabe von "hostname" in einer Variable HOST und gebt sie aus. | ||
| + | </pre> | ||
| + | |||
| + | == cut (Wiederholung aus 5101) == | ||
| + | |||
| + | <code>cut</code> zerschneidet Text an einem Trennzeichen: | ||
| + | |||
| + | <syntaxhighlight lang="bash"> | ||
| + | echo "server01.it2XX.int" | cut -d'.' -f1 | ||
| + | # server01 | ||
| + | echo "server01.it2XX.int" | cut -d'.' -f2- | ||
| + | # it2XX.int | ||
| + | </syntaxhighlight> | ||
| + | |||
| + | <code>-d'.'</code> setzt den Punkt als Trennzeichen, <code>-f1</code> nimmt das erste Feld, <code>-f2-</code> alles ab dem zweiten Feld bis zum Ende. | ||
| + | |||
| + | Kombiniert mit Kommandosubstitution lässt sich das Ergebnis direkt in eine Variable schreiben: | ||
| + | |||
| + | <syntaxhighlight lang="bash"> | ||
| + | SHORT=$(echo "server01.it2XX.int" | cut -d'.' -f1) | ||
| + | </syntaxhighlight> | ||
| + | |||
| + | ;Übung | ||
| + | <pre> | ||
| + | Zerlegt "server01.it2XX.int" mit cut und Kommandosubstitution in SHORT (server01) und DOM (it2XX.int). | ||
| + | </pre> | ||
| + | |||
= Bash-Crashkurs: Skripting-Grundlagen = | = Bash-Crashkurs: Skripting-Grundlagen = | ||
| Zeile 95: | Zeile 161: | ||
[[ -z "$FQDN" || -z "$ADDR" ]] | [[ -z "$FQDN" || -z "$ADDR" ]] | ||
</syntaxhighlight> | </syntaxhighlight> | ||
| + | |||
| + | {{Hinweis|<code>&&</code> und <code>||</code> werten nur so weit aus, wie nötig (Kurzschlussauswertung): Bei <code>A && B</code> wird <code>B</code> nur ausgeführt, wenn <code>A</code> wahr war; bei <code>A || B</code> wird <code>B</code> nur ausgeführt, wenn <code>A</code> unwahr war. Deshalb steht in <code>$?</code> nach <code>[[ ... ]] && echo "wahr" || echo "unwahr"</code> am Ende der Exit-Code des ausgeführten <code>echo</code>, nicht mehr der von <code>[[ ]]</code>.}} | ||
;Übung | ;Übung | ||
| Zeile 106: | Zeile 174: | ||
Prüft danach jeweils mit echo $?, ob euer Ergebnis mit dem Exit-Code übereinstimmt. | Prüft danach jeweils mit echo $?, ob euer Ergebnis mit dem Exit-Code übereinstimmt. | ||
</pre> | </pre> | ||
| + | |||
| + | == if == | ||
| + | |||
| + | <code>[[ ]]</code> allein tut noch nichts außer prüfen – erst <code>if</code> reagiert auf das Ergebnis: | ||
| + | |||
| + | <syntaxhighlight lang="bash"> | ||
| + | if [[ -z "$FQDN" ]]; then | ||
| + | echo "FQDN fehlt!" | ||
| + | exit 1 | ||
| + | fi | ||
| + | </syntaxhighlight> | ||
| + | |||
| + | Aufbau: <code>if BEDINGUNG; then</code> ... <code>fi</code> (schließt den Block, "if" rückwärts geschrieben). Optional gibt es <code>else</code> für den Alternativfall und <code>elif</code> für eine weitere Bedingung. | ||
| + | |||
| + | <syntaxhighlight lang="bash"> | ||
| + | if [[ -z "$FQDN" ]]; then | ||
| + | echo "FQDN fehlt!" | ||
| + | else | ||
| + | echo "FQDN ist $FQDN" | ||
| + | fi | ||
| + | </syntaxhighlight> | ||
| + | |||
| + | ;Übung | ||
| + | <pre> | ||
| + | Schreibt ein if, das prüft, ob die Variable ADDR leer ist. Falls ja: Fehlermeldung ausgeben und mit exit 1 abbrechen. | ||
| + | </pre> | ||
| + | |||
| + | == while == | ||
| + | |||
| + | <code>while</code> wiederholt einen Block, solange eine Bedingung wahr ist: | ||
| + | |||
| + | <syntaxhighlight lang="bash"> | ||
| + | i=1 | ||
| + | while [[ $i -le 3 ]]; do | ||
| + | echo "Durchlauf $i" | ||
| + | i=$((i+1)) | ||
| + | done | ||
| + | </syntaxhighlight> | ||
| + | |||
| + | <code>while BEDINGUNG; do</code> ... <code>done</code>. Wichtig: die Bedingung muss sich im Schleifenkörper irgendwann ändern, sonst läuft die Schleife endlos. | ||
| + | |||
| + | ;Übung | ||
| + | <pre> | ||
| + | Schreibt eine while-Schleife, die von 1 bis 5 zählt und jede Zahl ausgibt. | ||
| + | </pre> | ||
| + | |||
| + | == Heredoc == | ||
| + | |||
| + | Ein Heredoc schreibt mehrzeiligen Text in eine Datei, ohne für jede Zeile ein eigenes echo zu brauchen: | ||
| + | |||
| + | <syntaxhighlight lang="bash"> | ||
| + | cat <<HERE > /tmp/test.txt | ||
| + | Zeile 1 | ||
| + | Zeile 2 | ||
| + | HERE | ||
| + | </syntaxhighlight> | ||
| + | |||
| + | Alles zwischen <code><<HERE</code> und der abschließenden Zeile <code>HERE</code> wird an <code>cat</code> übergeben. <code>></code> schreibt (überschreibt) die Datei, <code>>></code> hängt an. Variablen werden innerhalb des Heredocs per Variablensubstitution ganz normal ersetzt: | ||
| + | |||
| + | <syntaxhighlight lang="bash"> | ||
| + | cat <<HERE > /tmp/test.txt | ||
| + | Adresse: $ADDR | ||
| + | HERE | ||
| + | </syntaxhighlight> | ||
| + | |||
| + | ;Übung | ||
| + | <pre> | ||
| + | Schreibt mit einem Heredoc eine Datei /tmp/netztest.txt, die die Werte von ADDR und DOM enthält. | ||
| + | </pre> | ||
| + | |||
| + | == Variablen übergeben über $1, $2, ... == | ||
| + | |||
| + | Beim Aufruf eines Skripts landen die übergebenen Werte automatisch in nummerierten Variablen: | ||
| + | |||
| + | <syntaxhighlight lang="bash"> | ||
| + | ./skript.sh server01 10.2XX.0.10 | ||
| + | |||
| + | echo "$1" # server01 | ||
| + | echo "$2" # 10.2XX.0.10 | ||
| + | </syntaxhighlight> | ||
| + | |||
| + | <code>$0</code> ist der Skriptname selbst, <code>$1</code> das erste Argument, <code>$2</code> das zweite, usw. <code>$#</code> gibt die Anzahl der übergebenen Argumente aus. | ||
| + | |||
| + | {{Hinweis|Diese Positionsparameter merken sich nur die Reihenfolge, nicht was gemeint ist. Der Aufrufer muss genau wissen, dass Argument 1 der FQDN ist und Argument 2 die Adresse. Vertauscht man die Reihenfolge, gibt es keine Fehlermeldung, nur falsche Werte.}} | ||
| + | |||
| + | ;Übung | ||
| + | <pre> | ||
| + | Schreibt ein Skript args.sh, das $1 und $2 ausgibt. Ruft es mit zwei, dann mit nur einem Argument auf. Was steht dann in $2? | ||
| + | </pre> | ||
| + | |||
| + | == Robuster mit getopts == | ||
| + | |||
| + | Das Problem von <code>$1</code>/<code>$2</code>: feste Reihenfolge, keine Namen, kein "diese Option ist optional". <code>getopts</code> löst das, indem Optionen mit Buchstaben und in beliebiger Reihenfolge übergeben werden: | ||
| + | |||
| + | <syntaxhighlight lang="bash"> | ||
| + | ./skript.sh -f server01.it2XX.int -a 10.2XX.0.10/24 | ||
| + | </syntaxhighlight> | ||
| + | |||
| + | statt | ||
| + | |||
| + | <syntaxhighlight lang="bash"> | ||
| + | ./skript.sh server01.it2XX.int 10.2XX.0.10/24 | ||
| + | </syntaxhighlight> | ||
| + | |||
| + | Ein Options-String wie <code>"f:a:"</code> legt fest, welche Buchstaben erlaubt sind. Ein Doppelpunkt hinter einem Buchstaben bedeutet: diese Option erwartet einen Wert. | ||
| + | |||
| + | <syntaxhighlight lang="bash"> | ||
| + | while getopts "f:a:" opt; do | ||
| + | case $opt in | ||
| + | f) FQDN="$OPTARG" ;; | ||
| + | a) ADDR="$OPTARG" ;; | ||
| + | *) echo "Ungültige Option" >&2; exit 1 ;; | ||
| + | esac | ||
| + | done | ||
| + | </syntaxhighlight> | ||
| + | |||
| + | <code>getopts</code> liest bei jedem Schleifendurchlauf die nächste Option. Der Buchstabe landet in <code>$opt</code>, ein eventueller Wert automatisch in <code>$OPTARG</code>. Im <code>case</code> wird pro Buchstabe die passende Variable befüllt. Der Zweig <code>*)</code> fängt unbekannte Optionen ab; <code>>&2</code> schickt die Fehlermeldung nach stderr, <code>exit 1</code> beendet das Skript mit Fehlercode. | ||
| + | |||
| + | ;Übung | ||
| + | <pre> | ||
| + | Schreibt ein Skript foo.sh, das die Optionen -f und -a mit getopts einliest und beide Werte ausgibt. | ||
| + | Testet danach: | ||
| + | ./foo.sh -f | ||
| + | ./foo.sh -z | ||
| + | Was landet in $opt in beiden Fällen? | ||
| + | </pre> | ||
| + | |||
| + | == Abschlussaufgabe: Das vollständige Skript == | ||
| + | |||
| + | Baut jetzt aus den Bausteinen oben ein Skript, das per Kommandozeile FQDN, IP-Adresse, Gateway und Nameserver entgegennimmt und daraus eine statische Netzwerkkonfiguration schreibt. | ||
| + | |||
| + | ;Anforderungen | ||
| + | * Optionen <code>-f</code> (FQDN), <code>-a</code> (Adresse/CIDR), <code>-g</code> (Gateway), <code>-n</code> (Nameserver), alle mit Wert, über getopts eingelesen | ||
| + | * Fehlt eine der vier Angaben, Fehlermeldung mit Nutzungshinweis und <code>exit 1</code> | ||
| + | * FQDN mit cut und Kommandosubstitution in <code>SHORT</code> und <code>DOM</code> zerlegen | ||
| + | * <code>/etc/network/interfaces</code> per Heredoc schreiben (Loopback + statisches Interface <code>enp0s3</code>) | ||
| + | * Hostname mit <code>hostnamectl set-hostname</code> setzen | ||
| + | |||
| + | {{Hinweis|Testet euer Skript zuerst mit fehlenden Optionen und mit einer unbekannten Option, bevor ihr den vollständigen Aufruf prüft.}} | ||
| + | |||
| + | [[Kategorie:Shellscripting]] | ||
| + | [[Kategorie:Linux Grundlagen]] | ||
== if == | == if == | ||
Version vom 11. Juli 2026, 12:48 Uhr
Bash-Crashkurs: Skripting-Grundlagen
Dieser Kurs vermittelt die Bash-Mechanismen, die für ein eigenes Skript zur Netzwerkkonfiguration gebraucht werden. Jeder Abschnitt führt einen Baustein ein. Am Ende schreibt ihr daraus selbst ein vollständiges Skript.
Variablensubstitution
Eine Variable wird ohne Leerzeichen um das = gesetzt:
NAME="server01"
Der Wert wird ausgelesen, indem man ein $ vor den Namen setzt – dieser Vorgang heißt Variablensubstitution: Bash ersetzt $NAME durch den gespeicherten Wert, bevor der Befehl ausgeführt wird.
echo $NAME
echo "$NAME"
In Anführungszeichen referenzieren, sonst gibt's bei Leerzeichen oder Sonderzeichen im Wert Probleme (Bash zerlegt den Wert sonst an Leerzeichen in mehrere Wörter).
- Übung
Setzt eine Variable ADDR mit dem Wert 10.2XX.0.10/24 und gebt sie einmal ohne und einmal mit Anführungszeichen aus.
Kommandosubstitution
Mit $(...) wird nicht der Text eines Befehls ausgeführt, sondern seine Ausgabe als Wert eingesetzt – das nennt man Kommandosubstitution:
DATUM=$(date +%Y-%m-%d)
echo "$DATUM"
$(date +%Y-%m-%d) wird zuerst ausgeführt, die Ausgabe des Befehls landet dann in DATUM.
- Übung
Speichert die Ausgabe von "hostname" in einer Variable HOST und gebt sie aus.
cut (Wiederholung aus 5101)
cut zerschneidet Text an einem Trennzeichen:
echo "server01.it2XX.int" | cut -d'.' -f1
# server01
echo "server01.it2XX.int" | cut -d'.' -f2-
# it2XX.int
-d'.' setzt den Punkt als Trennzeichen, -f1 nimmt das erste Feld, -f2- alles ab dem zweiten Feld bis zum Ende.
Kombiniert mit Kommandosubstitution lässt sich das Ergebnis direkt in eine Variable schreiben:
SHORT=$(echo "server01.it2XX.int" | cut -d'.' -f1)
- Übung
Zerlegt "server01.it2XX.int" mit cut und Kommandosubstitution in SHORT (server01) und DOM (it2XX.int).
Bash-Crashkurs: Skripting-Grundlagen
Dieser Kurs vermittelt die Bash-Mechanismen, die für ein eigenes Skript zur Netzwerkkonfiguration gebraucht werden. Jeder Abschnitt führt einen Baustein ein. Am Ende schreibt ihr daraus selbst ein vollständiges Skript.
Variablensubstitution
Eine Variable wird ohne Leerzeichen um das = gesetzt:
NAME="server01"
Der Wert wird ausgelesen, indem man ein $ vor den Namen setzt – dieser Vorgang heißt Variablensubstitution: Bash ersetzt $NAME durch den gespeicherten Wert, bevor der Befehl ausgeführt wird.
echo $NAME
echo "$NAME"
In Anführungszeichen referenzieren, sonst gibt's bei Leerzeichen oder Sonderzeichen im Wert Probleme (Bash zerlegt den Wert sonst an Leerzeichen in mehrere Wörter).
- Übung
Setzt eine Variable ADDR mit dem Wert 10.2XX.0.10/24 und gebt sie einmal ohne und einmal mit Anführungszeichen aus.
Kommandosubstitution
Mit $(...) wird nicht der Text eines Befehls ausgeführt, sondern seine Ausgabe als Wert eingesetzt – das nennt man Kommandosubstitution:
DATUM=$(date +%Y-%m-%d)
echo "$DATUM"
$(date +%Y-%m-%d) wird zuerst ausgeführt, die Ausgabe des Befehls landet dann in DATUM.
- Übung
Speichert die Ausgabe von "hostname" in einer Variable HOST und gebt sie aus.
cut (Wiederholung aus 5101)
cut zerschneidet Text an einem Trennzeichen:
echo "server01.it2XX.int" | cut -d'.' -f1
# server01
echo "server01.it2XX.int" | cut -d'.' -f2-
# it2XX.int
-d'.' setzt den Punkt als Trennzeichen, -f1 nimmt das erste Feld, -f2- alles ab dem zweiten Feld bis zum Ende.
Kombiniert mit Kommandosubstitution lässt sich das Ergebnis direkt in eine Variable schreiben:
SHORT=$(echo "server01.it2XX.int" | cut -d'.' -f1)
- Übung
Zerlegt "server01.it2XX.int" mit cut und Kommandosubstitution in SHORT (server01) und DOM (it2XX.int).
Testausdrücke: [[ ]]
[[ ]] prüft eine Bedingung und liefert wahr oder unwahr (als Exit-Code, 0 = wahr, ungleich 0 = unwahr):
[[ "$X" == 1 ]] # wahr, wenn X gleich 1 ist
[[ -z "$VAR" ]] # wahr, wenn VAR leer ist
[[ -n "$VAR" ]] # wahr, wenn VAR NICHT leer ist
Der Exit-Code des zuletzt ausgeführten Befehls steht in $?. Damit lässt sich sichtbar machen, was [[ ]] tatsächlich zurückgibt:
X=1
[[ "$X" == 1 ]]
echo $?
# 0 (wahr)
[[ "$X" == 2 ]]
echo $?
# 1 (unwahr)
Das ist auch genau das, was if später intern auswertet: if prüft nichts anderes als $? des Befehls direkt danach.
Mehrere Bedingungen lassen sich mit || (ODER) oder && (UND) verknüpfen:
[[ -z "$FQDN" || -z "$ADDR" ]]
ℹ️ Hinweis: && und
- Übung
Testet direkt auf der Kommandozeile:
X=1
[[ "$X" == 1 ]] && echo "wahr" || echo "unwahr"
X=""
[[ -z "$X" ]] && echo "leer" || echo "nicht leer"
Prüft danach jeweils mit echo $?, ob euer Ergebnis mit dem Exit-Code übereinstimmt.
if
[[ ]] allein tut noch nichts außer prüfen – erst if reagiert auf das Ergebnis:
if [[ -z "$FQDN" ]]; then
echo "FQDN fehlt!"
exit 1
fi
Aufbau: if BEDINGUNG; then ... fi (schließt den Block, "if" rückwärts geschrieben). Optional gibt es else für den Alternativfall und elif für eine weitere Bedingung.
if [[ -z "$FQDN" ]]; then
echo "FQDN fehlt!"
else
echo "FQDN ist $FQDN"
fi
- Übung
Schreibt ein if, das prüft, ob die Variable ADDR leer ist. Falls ja: Fehlermeldung ausgeben und mit exit 1 abbrechen.
while
while wiederholt einen Block, solange eine Bedingung wahr ist:
i=1
while [[ $i -le 3 ]]; do
echo "Durchlauf $i"
i=$((i+1))
done
while BEDINGUNG; do ... done. Wichtig: die Bedingung muss sich im Schleifenkörper irgendwann ändern, sonst läuft die Schleife endlos.
- Übung
Schreibt eine while-Schleife, die von 1 bis 5 zählt und jede Zahl ausgibt.
Heredoc
Ein Heredoc schreibt mehrzeiligen Text in eine Datei, ohne für jede Zeile ein eigenes echo zu brauchen:
cat <<HERE > /tmp/test.txt
Zeile 1
Zeile 2
HERE
Alles zwischen <<HERE und der abschließenden Zeile HERE wird an cat übergeben. > schreibt (überschreibt) die Datei, >> hängt an. Variablen werden innerhalb des Heredocs per Variablensubstitution ganz normal ersetzt:
cat <<HERE > /tmp/test.txt
Adresse: $ADDR
HERE
- Übung
Schreibt mit einem Heredoc eine Datei /tmp/netztest.txt, die die Werte von ADDR und DOM enthält.
Variablen übergeben über $1, $2, ...
Beim Aufruf eines Skripts landen die übergebenen Werte automatisch in nummerierten Variablen:
./skript.sh server01 10.2XX.0.10
echo "$1" # server01
echo "$2" # 10.2XX.0.10
$0 ist der Skriptname selbst, $1 das erste Argument, $2 das zweite, usw. $# gibt die Anzahl der übergebenen Argumente aus.
ℹ️ Hinweis: Diese Positionsparameter merken sich nur die Reihenfolge, nicht was gemeint ist. Der Aufrufer muss genau wissen, dass Argument 1 der FQDN ist und Argument 2 die Adresse. Vertauscht man die Reihenfolge, gibt es keine Fehlermeldung, nur falsche Werte.
- Übung
Schreibt ein Skript args.sh, das $1 und $2 ausgibt. Ruft es mit zwei, dann mit nur einem Argument auf. Was steht dann in $2?
Robuster mit getopts
Das Problem von $1/$2: feste Reihenfolge, keine Namen, kein "diese Option ist optional". getopts löst das, indem Optionen mit Buchstaben und in beliebiger Reihenfolge übergeben werden:
./skript.sh -f server01.it2XX.int -a 10.2XX.0.10/24
statt
./skript.sh server01.it2XX.int 10.2XX.0.10/24
Ein Options-String wie "f:a:" legt fest, welche Buchstaben erlaubt sind. Ein Doppelpunkt hinter einem Buchstaben bedeutet: diese Option erwartet einen Wert.
while getopts "f:a:" opt; do
case $opt in
f) FQDN="$OPTARG" ;;
a) ADDR="$OPTARG" ;;
*) echo "Ungültige Option" >&2; exit 1 ;;
esac
done
getopts liest bei jedem Schleifendurchlauf die nächste Option. Der Buchstabe landet in $opt, ein eventueller Wert automatisch in $OPTARG. Im case wird pro Buchstabe die passende Variable befüllt. Der Zweig *) fängt unbekannte Optionen ab; >&2 schickt die Fehlermeldung nach stderr, exit 1 beendet das Skript mit Fehlercode.
- Übung
Schreibt ein Skript foo.sh, das die Optionen -f und -a mit getopts einliest und beide Werte ausgibt.
Testet danach:
./foo.sh -f
./foo.sh -z
Was landet in $opt in beiden Fällen?
Abschlussaufgabe: Das vollständige Skript
Baut jetzt aus den Bausteinen oben ein Skript, das per Kommandozeile FQDN, IP-Adresse, Gateway und Nameserver entgegennimmt und daraus eine statische Netzwerkkonfiguration schreibt.
- Anforderungen
- Optionen
-f (FQDN), -a (Adresse/CIDR), -g (Gateway), -n (Nameserver), alle mit Wert, über getopts eingelesen
- Fehlt eine der vier Angaben, Fehlermeldung mit Nutzungshinweis und
exit 1
- FQDN mit cut und Kommandosubstitution in
SHORT und DOM zerlegen
/etc/network/interfaces per Heredoc schreiben (Loopback + statisches Interface enp0s3)
- Hostname mit
hostnamectl set-hostname setzen
ℹ️ Hinweis: Testet euer Skript zuerst mit fehlenden Optionen und mit einer unbekannten Option, bevor ihr den vollständigen Aufruf prüft.
if
[[ ]] allein tut noch nichts außer prüfen – erst if reagiert auf das Ergebnis:
if [[ -z "$FQDN" ]]; then
echo "FQDN fehlt!"
exit 1
fi
Aufbau: if BEDINGUNG; then ... fi (schließt den Block, "if" rückwärts geschrieben). Optional gibt es else für den Alternativfall und elif für eine weitere Bedingung.
if [[ -z "$FQDN" ]]; then
echo "FQDN fehlt!"
else
echo "FQDN ist $FQDN"
fi
- Übung
Schreibt ein if, das prüft, ob die Variable ADDR leer ist. Falls ja: Fehlermeldung ausgeben und mit exit 1 abbrechen.
while
while wiederholt einen Block, solange eine Bedingung wahr ist:
i=1
while [[ $i -le 3 ]]; do
echo "Durchlauf $i"
i=$((i+1))
done
while BEDINGUNG; do ... done. Wichtig: die Bedingung muss sich im Schleifenkörper irgendwann ändern, sonst läuft die Schleife endlos.
- Übung
Schreibt eine while-Schleife, die von 1 bis 5 zählt und jede Zahl ausgibt.
Heredoc
Ein Heredoc schreibt mehrzeiligen Text in eine Datei, ohne für jede Zeile ein eigenes echo zu brauchen:
cat <<HERE > /tmp/test.txt
Zeile 1
Zeile 2
HERE
Alles zwischen <<HERE und der abschließenden Zeile HERE wird an cat übergeben. > schreibt (überschreibt) die Datei, >> hängt an. Variablen werden innerhalb des Heredocs per Variablensubstitution ganz normal ersetzt:
cat <<HERE > /tmp/test.txt
Adresse: $ADDR
HERE
- Übung
Schreibt mit einem Heredoc eine Datei /tmp/netztest.txt, die die Werte von ADDR und DOM enthält.
Variablen übergeben über $1, $2, ...
Beim Aufruf eines Skripts landen die übergebenen Werte automatisch in nummerierten Variablen:
./skript.sh server01 10.2XX.0.10
echo "$1" # server01
echo "$2" # 10.2XX.0.10
$0 ist der Skriptname selbst, $1 das erste Argument, $2 das zweite, usw. $# gibt die Anzahl der übergebenen Argumente aus.
ℹ️ Hinweis: Diese Positionsparameter merken sich nur die Reihenfolge, nicht was gemeint ist. Der Aufrufer muss genau wissen, dass Argument 1 der FQDN ist und Argument 2 die Adresse. Vertauscht man die Reihenfolge, gibt es keine Fehlermeldung, nur falsche Werte.
- Übung
Schreibt ein Skript args.sh, das $1 und $2 ausgibt. Ruft es mit zwei, dann mit nur einem Argument auf. Was steht dann in $2?
Robuster mit getopts
Das Problem von $1/$2: feste Reihenfolge, keine Namen, kein "diese Option ist optional". getopts löst das, indem Optionen mit Buchstaben und in beliebiger Reihenfolge übergeben werden:
./skript.sh -f server01.it2XX.int -a 10.2XX.0.10/24
statt
./skript.sh server01.it2XX.int 10.2XX.0.10/24
Ein Options-String wie "f:a:" legt fest, welche Buchstaben erlaubt sind. Ein Doppelpunkt hinter einem Buchstaben bedeutet: diese Option erwartet einen Wert.
while getopts "f:a:" opt; do
case $opt in
f) FQDN="$OPTARG" ;;
a) ADDR="$OPTARG" ;;
*) echo "Ungültige Option" >&2; exit 1 ;;
esac
done
getopts liest bei jedem Schleifendurchlauf die nächste Option. Der Buchstabe landet in $opt, ein eventueller Wert automatisch in $OPTARG. Im case wird pro Buchstabe die passende Variable befüllt. Der Zweig *) fängt unbekannte Optionen ab; >&2 schickt die Fehlermeldung nach stderr, exit 1 beendet das Skript mit Fehlercode.
- Übung
Schreibt ein Skript foo.sh, das die Optionen -f und -a mit getopts einliest und beide Werte ausgibt.
Testet danach:
./foo.sh -f
./foo.sh -z
Was landet in $opt in beiden Fällen?
Abschlussaufgabe: Das vollständige Skript
Baut jetzt aus den Bausteinen oben ein Skript, das per Kommandozeile FQDN, IP-Adresse, Gateway und Nameserver entgegennimmt und daraus eine statische Netzwerkkonfiguration schreibt.
- Anforderungen
- Optionen
-f (FQDN), -a (Adresse/CIDR), -g (Gateway), -n (Nameserver), alle mit Wert, über getopts eingelesen
- Fehlt eine der vier Angaben, Fehlermeldung mit Nutzungshinweis und
exit 1
- FQDN mit cut und Kommandosubstitution in
SHORT und DOM zerlegen
/etc/network/interfaces per Heredoc schreiben (Loopback + statisches Interface enp0s3)
- Hostname mit
hostnamectl set-hostname setzen
ℹ️ Hinweis: Testet euer Skript zuerst mit fehlenden Optionen und mit einer unbekannten Option, bevor ihr den vollständigen Aufruf prüft.