Das erste Skript
Jedes neue Skript beginnt mit denselben Kopfzeilen, dann chmod +x, dann den Editor öffnen. Das ist Tipparbeit, die sich automatisieren lässt. Genau das macht addscript.sh, das du auf dieser Seite in kleinen Schritten baust. Nebenbei lernst du alles kennen, was ein Skript ausmacht.
Was ein Skript ist
Abschnitt betitelt „Was ein Skript ist“Ein Shell-Skript ist eine Textdatei mit Befehlen. Die Shell liest sie von oben nach unten und führt Zeile für Zeile aus, als hättest du sie getippt. Drei Dinge braucht es, damit das klappt:
- Die erste Zeile, der Shebang, sagt dem System, welcher Interpreter das Skript ausführen soll:
hallo.sh #!/bin/bashecho "Hallo $(whoami), heute ist $(date +%A)." - Die Datei muss ausführbar sein:
Terminal-Fenster chmod +x hallo.sh - Der Aufruf braucht einen Pfad, weil die Shell Programme nur in den Verzeichnissen aus
$PATHsucht und das aktuelle Verzeichnis nicht dazugehört:Terminal-Fenster ./hallo.sh
Ohne x-Bit geht es auch mit bash hallo.sh, dann ist der Shebang egal. Üblich ist aber der Aufruf mit ./.
Die Konvention
Abschnitt betitelt „Die Konvention“Skripte in diesem Kurs beginnen alle mit demselben Kopf. Er beantwortet die Fragen, die man sich drei Monate später stellt: Was macht das Ding, wer hat es geschrieben, wann?
#!/bin/bash## skriptname.sh# Zweck des Skripts, gerne auch über mehrere Zeilen## 2026-11-05 / Vorname Nachname#
# Variablen
# Funktionen
# HauptprogrammDie drei Abschnitte halten Ordnung: zuerst alle Variablen, dann die Funktionen (ab Teil 3), dann der eigentliche Ablauf. Die Details stehen in der Skript-Konvention.
Das Ziel: addscript.sh
Abschnitt betitelt „Das Ziel: addscript.sh“Das Skript soll ein neues Skript mit genau diesem Kopf anlegen, es ausführbar machen und im Editor öffnen. Als Flowchart:
flowchart TD
S(["Start"]) --> W["Template in Datei schreiben"]
W --> X["Datei ausführbar machen"]
X --> E["Editor öffnen"]
E --> Z(["Ende"])
Ovale sind Start und Ende, Rechtecke sind Operationen. Später kommen Rauten für Verzweigungen dazu. Flowcharts zeichnest du in diesem Kurs als Mermaid, eine Textnotation, die GitLab und diese Webseite direkt als Diagramm anzeigen. Den Quelltext des Diagramms oben findest du in der Lösung von Aufgabe 8.2.
Listing 1: Ausgabe umleiten
Abschnitt betitelt „Listing 1: Ausgabe umleiten“Wechsle in dein Kurs-Repository, lege labs/linux/08-skripte/ an und erstelle darin addscript.sh:
#!/bin/bash## addscript.sh# Erstellt ein Skript aus dem Kurs-Template, macht es# ausführbar und öffnet es im Editor.## 2026-11-05 / Vorname Nachname#
# Hauptprogramm
# Template mit echo ausgeben und in die Datei umleitenecho "#!/bin/bash## newscript.sh# Zweck des Skripts## Datum / Name#
# Variablen
# Funktionen
# Hauptprogramm" > newscript.sh
# Ausführbar machen und im Editor öffnenchmod +x newscript.shvim newscript.shEin echo mit mehrzeiligem Text in Anführungszeichen, dessen Ausgabe mit > in eine Datei umgeleitet wird. Danach chmod und der Editor. Wer lieber nano oder code verwendet, ersetzt vim. Trage dein Datum und deinen Namen ein.
Testen. Mach das Skript ausführbar und überlege, bevor du es startest: Was sollte passieren? Woran erkennst du nachher, dass es funktioniert hat?
cd labs/linux/08-skriptechmod +x addscript.sh./addscript.shls -lcat newscript.shListing 2: Eine Variable
Abschnitt betitelt „Listing 2: Eine Variable“Das Skript ist starr: Es erzeugt immer newscript.sh und überschreibt eine vorhandene Datei ohne Warnung. Erster Schritt zur Besserung: Der Dateiname kommt in eine Variable. Markiert sind die Zeilen, die neu sind oder sich ändern.
#!/bin/bash## addscript.sh# Erstellt ein Skript aus dem Kurs-Template, macht es# ausführbar und öffnet es im Editor.## 2026-11-05 / Vorname Nachname#
# Variablendateiname="test.sh"
# Hauptprogramm
# Template mit echo ausgeben und in die Datei umleitenecho "#!/bin/bash## $dateiname# Zweck des Skripts## Datum / Name#
# Variablen
# Funktionen
# Hauptprogramm" > "$dateiname"
# Ausführbar machen und im Editor öffnenchmod +x "$dateiname"vim "$dateiname"Eine Variable hat einen Namen und einen Wert. Zugewiesen wird mit = ohne Leerzeichen daneben, gelesen mit $dateiname. Variablen stehen beim Lesen immer in doppelten Anführungszeichen: So bleibt ein Wert mit Leerzeichen ein Wert, und ShellCheck ist zufrieden. Innerhalb von "..." werden Variablen ersetzt, innerhalb von '...' nicht.
Richtig, das Ganze bringt noch wenig. Kommt gleich. Testen trotzdem, der Code hat sich geändert: Was erwartest du?
Argumente
Abschnitt betitelt „Argumente“Richtig flexibel wird addscript.sh, wenn der Dateiname beim Aufruf mitgegeben wird: ./addscript.sh backup.sh. Dafür stellt die Bash spezielle Variablen bereit, die sie beim Start automatisch füllt. Schau sie dir mit einem kleinen Demo-Skript an:
#!/bin/bash## argumente.sh# Zeigt, wie die Bash Argumente an ein Skript übergibt.## 2026-11-05 / Vorname Nachname#
# Hauptprogrammecho "Der Skriptname: $0"echo "Anzahl Argumente: $#"echo "Alle Argumente: $*"echo "Das 1. Argument: $1"echo "Das 2. Argument: $2"echo "Das 3. Argument: $3"chmod +x argumente.sh./argumente.sh so geht das./argumente.sh "so geht" dasWas erwartest du beim zweiten Aufruf? Die Anführungszeichen fassen zwei Wörter zu einem Argument zusammen.
| Variable | Inhalt |
|---|---|
$0 |
Name des Skripts, so wie es aufgerufen wurde |
$1 bis $9 |
erstes bis neuntes Argument, ab dem zehnten ${10} |
$# |
Anzahl der Argumente |
$* |
alle Argumente als ein String |
"$@" |
alle Argumente, jedes einzeln (für Schleifen, nächste Seite) |
$? |
Exit-Status des zuletzt ausgeführten Befehls |
Listing 3: Der Dateiname als Argument
Abschnitt betitelt „Listing 3: Der Dateiname als Argument“In addscript.sh ist nur eine Zeile zu ändern. Die feste Zuweisung fliegt raus, das erste Argument kommt rein:
# Variablendateiname="test.sh"dateiname="$1"Testen. Was erwartest du?
./addscript.sh neu.sh./addscript.sh auch.shls -lDer eingebaute Fehler
Abschnitt betitelt „Der eingebaute Fehler“Die schöne Änderung hat ein Loch. Hast du es bemerkt? Ruf das Skript ohne Argument auf:
./addscript.shDie Shell meldet No such file or directory, chmod beschwert sich, und der Editor öffnet irgendetwas, nur nicht das, was du wolltest. Nicht gerade ein Verhalten, das gute Software auszeichnet. Das Skript muss seine Argumente prüfen und bei Bedarf abbrechen. Dazu braucht es Bedingungen.
Bedingungen und Exit-Codes
Abschnitt betitelt „Bedingungen und Exit-Codes“Eine Verzweigung sieht in der Bash so aus:
if [[ bedingung ]]; then befehle # wenn die Bedingung wahr istelse befehle # sonstfiDer else-Teil ist optional. Die Bedingung steht in doppelten eckigen Klammern. Historisch ist [ ein eigenes Programm (test), [[ ]] ist die eingebaute, bequemere Bash-Variante: Sie erlaubt && und || innerhalb der Klammern und kommt mit leeren Variablen besser zurecht. In Bash-Skripten verwenden wir immer [[ ]]. Die wichtigsten Tests:
| Test | wahr, wenn |
|---|---|
-e datei |
die Datei existiert (egal welcher Typ) |
-f datei |
es eine normale Datei ist |
-d pfad |
es ein Verzeichnis ist |
-r, -w, -x datei |
lesbar, schreibbar, ausführbar |
-z "$s" |
der String leer ist |
-n "$s" |
der String nicht leer ist |
"$a" == "$b", "$a" != "$b" |
Strings gleich, ungleich |
$x -eq $y |
Zahlen gleich, dazu -ne, -lt, -le, -gt, -ge |
! bedingung |
die Bedingung nicht wahr ist |
Jede Bedingung ist ein Befehl mit einem Exit-Status: 0 heisst wahr beziehungsweise erfolgreich, alles andere falsch beziehungsweise Fehler. Dasselbe gilt für dein ganzes Skript. Mit exit 0 endet es regulär, mit exit 1 (oder einer anderen Zahl ungleich 0) meldet es einen Fehler. Wer das Skript aufruft, sieht den Wert in $? und kann darauf reagieren, etwa mit ./addscript.sh x.sh && echo "ok".
Probiere das Demo-Skript scripts/linux/08-skripte/testdemo.sh aus dem Repository aus, es führt alle Tests einmal vor.
Für addscript.sh heisst das: Fehlt das Argument, Hinweis ausgeben und mit exit 1 abbrechen. Im Flowchart kommt eine Raute dazu, und es gibt neu zwei Enden:
flowchart TD
S(["Start"]) --> P{"Argument vorhanden?"}
P -->|nein| M["Benutzung ausgeben"] --> E1(["Ende, exit 1"])
P -->|ja| W["Template in Datei schreiben"]
W --> X["Datei ausführbar machen"]
X --> ED["Editor öffnen"]
ED --> E0(["Ende, exit 0"])
Listing 4: Argument prüfen
Abschnitt betitelt „Listing 4: Argument prüfen“# Variablendateiname="$1"benutzung="Benutzung: $0 skriptname.sh"
# Hauptprogramm
# Aufruf prüfen, im Fehlerfall Hinweis ausgeben und abbrechenif [[ $# -lt 1 ]]; then echo "$benutzung" exit 1fiAuf Deutsch: Wenn die Anzahl Argumente kleiner als 1 ist, dann Benutzung ausgeben und mit Status 1 abbrechen. Der Block gehört an den Anfang des Hauptprogramms, vor das echo mit dem Template.
Testen mit null, einem und zwei Argumenten. Prüfe jeweils den Exit-Status:
./addscript.shecho $?./addscript.sh zwei.shecho $?Komfort: Datum und Name automatisch
Abschnitt betitelt „Komfort: Datum und Name automatisch“Die Felder «Datum / Name» im Kopf soll addscript.sh selbst ausfüllen. Das Datum liefert date, mit einem Format-String auf Tag.Monat.Jahr reduziert, den Login-Namen whoami:
date +%d.%m.%Ywhoamigetent passwd "$USER" | cut -d: -f5 | cut -d, -f1Der dritte Befehl holt den vollständigen Namen aus /etc/passwd (Feld 5, bis zum ersten Komma), falls er bei der Installation angegeben wurde. Um die Ausgabe eines Befehls in einer Variablen zu speichern, dient die Befehlssubstitution $(befehl): Die Shell führt den Befehl aus und setzt seine Ausgabe an dieser Stelle ein.
Listing 5: Datum und Verfasser
Abschnitt betitelt „Listing 5: Datum und Verfasser“# Variablendateiname="$1"benutzung="Benutzung: $0 skriptname.sh"datum=$(date +%d.%m.%Y)verfasser=$(whoami)# Zweck des Skripts## Datum / Name# $datum / $verfasser#Testen. Wie nach jeder Änderung. Stimmt der Kopf des erzeugten Skripts?
Sicherheit: Nicht überschreiben
Abschnitt betitelt „Sicherheit: Nicht überschreiben“Noch prüft addscript.sh nicht, ob die Zieldatei schon existiert. Fatal, wenn ein mit viel Hirnschmalz geschriebenes Skript durch den Generator einfach überschrieben würde. Der Test dafür steht in der Tabelle oben: -e.
Listing 6: Existenz prüfen
Abschnitt betitelt „Listing 6: Existenz prüfen“Füge den Block direkt nach der Argumentprüfung ein:
# Aufruf prüfen, im Fehlerfall Hinweis ausgeben und abbrechenif [[ $# -lt 1 ]]; then echo "$benutzung" exit 1fi
# Abbruch, falls die Datei bereits existiertif [[ -e "$dateiname" ]]; then echo "$0: Fehler, $dateiname existiert bereits." exit 1fiTesten. Nimm als Argument zuerst eine Datei, um die es nicht schade wäre. Sicher ist sicher.
./addscript.sh neu.shecho $?Der Stand jetzt
Abschnitt betitelt „Der Stand jetzt“Zur Kontrolle das vollständige Skript:
#!/bin/bash## addscript.sh# Erstellt ein Skript aus dem Kurs-Template, macht es# ausführbar und öffnet es im Editor.## 2026-11-05 / Vorname Nachname#
# Variablendateiname="$1"benutzung="Benutzung: $0 skriptname.sh"datum=$(date +%d.%m.%Y)verfasser=$(whoami)
# Hauptprogramm
# Aufruf prüfen, im Fehlerfall Hinweis ausgeben und abbrechenif [[ $# -lt 1 ]]; then echo "$benutzung" exit 1fi
# Abbruch, falls die Datei bereits existiertif [[ -e "$dateiname" ]]; then echo "$0: Fehler, $dateiname existiert bereits." exit 1fi
# Template mit echo ausgeben und in die Datei umleitenecho "#!/bin/bash## $dateiname# Zweck des Skripts## $datum / $verfasser#
# Variablen
# Funktionen
# Hauptprogramm" > "$dateiname"
# Ausführbar machen und im Editor öffnenchmod +x "$dateiname"vim "$dateiname"Das Flowchart weiter oben stimmt damit nicht mehr. Das ist Teil deiner Aufgabe.
Lösung anzeigen
Das Skript mit allen Schritten. Die Variable programm ersetzt $0 in den Meldungen, damit nicht ./addscript.sh dort steht, sondern nur der Name:
#!/bin/bash## addscript.sh# Erstellt ein Skript aus dem Kurs-Template, macht es# ausführbar und öffnet es im Editor.## Benutzung: addscript.sh skriptname.sh ["Zweck des Skripts"]## 2026-11-05 / Vorname Nachname#
# Variablendateiname="$1"programm=$(basename "$0")benutzung="Benutzung: $programm skriptname.sh [\"Zweck des Skripts\"]"datum=$(date +%d.%m.%Y)# Vollständiger Name aus /etc/passwd (Feld 5, bis zum ersten Komma).# Falls das Feld leer ist, stattdessen: verfasser=$(whoami)verfasser=$(getent passwd "$USER" | cut -d: -f5 | cut -d, -f1)
# Hauptprogramm
# Aufruf prüfen: mindestens ein Argumentif [[ $# -lt 1 ]]; then echo "$benutzung" exit 1fi
# Abbruch, falls die Datei bereits existiertif [[ -e "$dateiname" ]]; then echo "$programm: Fehler, $dateiname existiert bereits." exit 1fi
# Zweck als zweites Argument, sonst nachfragenif [[ -n "$2" ]]; then zweck="$2"else read -r -p "Zweck des Skripts: " zweckfi
# Template mit echo ausgeben und in die Datei umleitenecho "#!/bin/bash## $dateiname# $zweck## $datum / $verfasser#
# Variablen
# Funktionen
# Hauptprogramm" > "$dateiname"
# Ausführbar machen und im Editor öffnenchmod +x "$dateiname"vim "$dateiname"Das Flowchart dazu:
flowchart TD
S(["Start"]) --> P{"Argument vorhanden?"}
P -->|nein| M["Benutzung ausgeben"] --> E1(["Ende, exit 1"])
P -->|ja| EX{"Datei existiert schon?"}
EX -->|ja| F["Fehlermeldung ausgeben"] --> E2(["Ende, exit 1"])
EX -->|nein| Z{"Zweck als 2. Argument?"}
Z -->|nein| R["Zweck mit read abfragen"] --> W
Z -->|ja| W["Template in Datei schreiben"]
W --> X["Datei ausführbar machen"]
X --> ED["Editor öffnen"]
ED --> E0(["Ende, exit 0"])Und der Quelltext für addscript-flowchart.md:
# Flowchart addscript.sh
```mermaidflowchart TD S(["Start"]) --> P{"Argument vorhanden?"} P -->|nein| M["Benutzung ausgeben"] --> E1(["Ende, exit 1"]) P -->|ja| EX{"Datei existiert schon?"} EX -->|ja| F["Fehlermeldung ausgeben"] --> E2(["Ende, exit 1"]) EX -->|nein| Z{"Zweck als 2. Argument?"} Z -->|nein| R["Zweck mit read abfragen"] --> W Z -->|ja| W["Template in Datei schreiben"] W --> X["Datei ausführbar machen"] X --> ED["Editor öffnen"] ED --> E0(["Ende, exit 0"])```Selbstcheck · 6 Fragen