- 1 Section
- 10 Lessons
- unbegrenzt
- Bash / Shell-Scripting10
- 1.1Was ist eine Shell? bash, sh, zsh im Vergleich
- 1.2Grundlegende Befehle: cd, ls, cp, mv, rm, grep
- 1.3Variablen, Eingabe und Ausgabe
- 1.4Kontrollstrukturen: if, case, for, while
- 1.5Funktionen und Argumente
- 1.6Fehlerbehandlung: exit codes, trap
- 1.7Textverarbeitung: sed, awk, cut, sort
- 1.8Dateisystem-Automation: find, xargs, cron
- 1.9Netzwerk-Scripting: curl, ssh, rsync
- 1.10Praxisprojekt: Systemstatus- und Backup-Script
Variablen, Eingabe und Ausgabe
Bisher hast du Befehle direkt eingetippt. Aber sobald deine Skripte wachsen, brauchst du Variablen – zum Speichern von Pfaden, Konfigurationen, Benutzereingaben. Außerdem brauchst du Möglichkeiten Ausgaben zu kontrollieren: in eine Datei umlenken, an einen anderen Befehl weiterreichen, Fehler von normalen Ausgaben trennen. Genau darum geht es in dieser Lektion.
Bash-Variablen sehen einfach aus – aber das Konzept der drei Streams (stdin, stdout, stderr) und das saubere Quoting sind Themen wo viele Anfänger stolpern. Wer diese Lektion verinnerlicht, schreibt deutlich robustere Skripte.
1) Variablen anlegen und benutzen
In Bash legst du eine Variable an mit name=wert. Wichtig: KEINE Leerzeichen um das Gleichheitszeichen – das ist ein häufiger Anfängerfehler. Auslesen mit Dollarzeichen davor:
name="Anna"
alter=25
projekt_pfad="/home/anna/projekte"
# Auslesen mit $
echo "Hallo $name, du bist $alter Jahre alt"
echo "Projekt liegt unter $projekt_pfad"
# FALSCH – Leerzeichen wirft Fehler
name = "Anna" # SyntaxError: command 'name' not found
Konventionen: Variablennamen in snake_case mit Kleinbuchstaben für eigene Variablen, UPPER_CASE für Konstanten und Umgebungsvariablen. Erlaubt: Buchstaben, Ziffern, Unterstrich – aber das erste Zeichen darf keine Ziffer sein. Bash kennt im Gegensatz zu Python oder Java nur einen einzigen Typ: String. Auch Zahlen sind technisch Strings (außer in arithmetischen Kontexten).
2) Quoting: einfach, doppelt, gar nicht?
Eine der wichtigsten Bash-Lektionen: Anführungszeichen sind nicht optional. Es gibt drei Quoting-Stile mit unterschiedlicher Bedeutung:
"$datei" statt $datei. Sonst zerbricht alles bei Pfaden mit Leerzeichen, bei Glob-Mustern oder Sonderzeichen. Das ist DIE häufigste Quelle von Bash-Bugs in der Praxis. ShellCheck (linter) warnt zu Recht in diesen Fällen.3) Die drei Streams: stdin, stdout, stderr
Jedes laufende Programm in Unix hat drei eingebaute „Datenkanäle". Wer das versteht, beherrscht Pipes und Ausgabe-Umleitung souverän:
stdout (1): Normale Ausgabe. Das was
echo, ls, cat ausgeben.stderr (2): Fehlermeldungen und Warnungen. Standardmäßig auch auf dem Terminal, aber unabhängig vom stdout-Stream.
befehl | weiteres-tool reicht nur stdout weiter. Fehler landen NICHT in der Pipe und stören die nächste Verarbeitung nicht. Das hat sich über Jahrzehnte bewährt – und ist Pflicht-Wissen für jeden, der Pipes baut.4) Umleitung: >, >>, 2>
Mit Umleitungs-Operatoren schickst du Streams in Dateien oder andere Streams:
ls > dateiliste.txt
# stdout ANHÄNGEN (existierende Datei wächst)
date >> log.txt
# stderr separat umleiten
befehl 2> errors.log
# Beide Streams in DIE SELBE Datei
befehl > all.log 2>&1
# oder kurz (Bash):
befehl &> all.log
# Stille machen: in /dev/null werfen ("ins Nichts")
befehl 2> /dev/null
befehl &> /dev/null
# Eingabe aus Datei
sort < namen.txt
Die Schreibweise 2>&1 wirkt erstmal kryptisch – bedeutet: „leite stderr (2) dort hin wo gerade auch stdout (1) hingeht". /dev/null ist das Schwarze Loch von Unix – alles was da reingeschrieben wird, ist weg. Praktisch um lästige Ausgaben zu unterdrücken.
5) Eingabe lesen mit read
Für interaktive Skripte gibt es read – wartet auf Tastatur-Eingabe und speichert sie in einer Variable:
read -p "Wie heißt du? " name
read -p "Wie alt? " alter
echo "Hallo $name, in 10 Jahren bist du $((alter + 10))"
# Mehrere Worte auf einmal
read -p "Vor- und Nachname: " vor nach
# Passwort-Eingabe ohne Echo
read -sp "Passwort: " pw
echo # Zeilenumbruch nach silent-read
Wichtige Optionen: -p "Text" zeigt einen Prompt. -s silent (für Passwörter). -t 10 Timeout in Sekunden. -n 1 nur ein Zeichen einlesen. $((...)) ist arithmetic expansion – damit kannst du in Bash rechnen.
6) Argumente: $1, $2, $@ – Kommandozeilen-Parameter
Wenn dein Skript Argumente vom User bekommt (./mein-script.sh datei1 datei2), sind sie über spezielle Variablen abrufbar:
# Aufruf: ./script.sh datei.txt backup/
echo "Skriptname: $0" # ./script.sh
echo "Erstes Argument: $1" # datei.txt
echo "Zweites: $2" # backup/
echo "Anzahl: $#" # 2
echo "Alle: $@" # datei.txt backup/
Mehr zu Argumenten und Argument-Parsing in L5 Funktionen – die gleichen Variablen werden auch innerhalb von Funktionen genutzt.
7) Parameter-Expansion: $-Magie
Bash hat eine extrem mächtige Syntax um Variablen-Inhalte direkt zu manipulieren – ohne externe Tools. Hier die wichtigsten:
sed oder cut (siehe L7). Typische Anwendung: ${datei%.txt}.bak macht aus notes.txt ein notes.bak. Oder: ${pfad##*/ liefert nur den Dateinamen aus einem vollen Pfad (gleicher Effekt wie basename).8) Umgebungsvariablen – das System kennenlernen
Bash hat von Haus aus dutzende Variablen die das System beschreiben. env oder printenv listet alle, set zeigt auch Shell-interne. Die wichtigsten:
export NAME=wert. Ohne export ist sie nur in der aktuellen Shell sichtbar, nicht in von dieser gestarteten Programmen. Persistente Umgebungs-Settings kommen in ~/.bashrc oder ~/.bash_profile. Mehr zum Exit-Code $? in L6 Fehlerbehandlung.9) echo und printf – Ausgabe schreiben
echo kennst du schon. Für formatierte Ausgaben ist printf präziser und vorhersagbarer – ähnlich wie in C:
echo "Hallo Welt"
echo -n "Ohne Zeilenumbruch" # -n
echo -e "Mit\\tTab und\\nZeile" # -e für Escapes
# printf – portabel, präzise
printf "Hallo %s, du bist %d Jahre alt\\n" "Anna" 25
printf "Preis: %.2f €\\n" 19.95
printf "Tabelle: %-10s %5d\\n" "Anna" 85
Format-Spezifier: %s String, %d Integer, %f Float, %.2f mit 2 Nachkommastellen, %-10s linksbündig 10 Zeichen, %5d rechtsbündig 5 Zeichen. printf fügt KEIN \n hinzu – musst du selbst setzen.
10) Heredoc – mehrzeilige Strings
Wenn du längeren Text ausgeben oder einem Befehl als Input geben willst, ist Heredoc elegant:
cat <<EOF > config.txt
[server]
host=localhost
port=8080
user=$USER # Variablen werden expandiert
EOF
# Mit Anführungszeichen um EOF: KEINE Expansion
cat <<'EOF'
Hier ist $USER nicht ersetzt
EOF
# <<- entfernt führende Tabs (für saubere Einrückung)
cat <<-EOF
Eingerückt im Code,
aber Tabs entfernt
EOF
<<MARKER startet, alles bis zum nächsten MARKER in einer eigenen Zeile ist der Text. EOF ist Konvention, du kannst aber jedes Wort nehmen. Sehr nützlich für: SQL-Statements, JSON, Konfigurations-Dateien, längere Hilfe-Texte in Skripten. Vermeidet ewige echo "..."-Stapel.11) Arrays in Bash
Bash kennt auch Arrays – allerdings mit etwas eigener Syntax:
farben=("rot" "grün" "blau")
# Zugriff: ${array[index]}
echo "${farben[0]}" # rot
echo "${farben[@]}" # alle
echo "${#farben[@]}" # Anzahl: 3
# Erweitern
farben+=("gelb")
# Iterieren (mehr in L4)
for farbe in "${farben[@]}"; do
echo "$farbe"
done
# Assoziative Arrays (key/value) – wie Python-dict
declare -A user
user[name]="Anna"
user[alter]=25
echo "${user[name]}"
Bash-Arrays sind etwas unhandlicher als in Python. Für komplexe Datenstrukturen lieber zu Python oder Perl greifen. Für einfache Listen reichen sie aber gut. Wichtig: bei der Iteration immer "${array[@]}" in Quotes – sonst zerbricht es bei Elementen mit Leerzeichen.
Zusammenfassung
Variablen: name=wert (KEIN Leerzeichen!), Auslesen mit $name oder ${name}. Quoting: "..." mit Variablen-Ersetzung, '...' literal, $(...) Command Substitution. Variablen IMMER in Doppel-Quotes packen! Drei Streams: stdin (0), stdout (1), stderr (2). Umleitung: > Datei (überschreibt), >> anhängen, 2> stderr, 2>&1 stderr in stdout, /dev/null ins Nichts. read -p für Eingabe (-s silent). Argumente: $0 Skript, $1, $2, ... Args, $# Anzahl, $@ alle. Parameter-Expansion: ${var:-default}, ${#var}, ${var%suffix}, ${var/such/ersetz}. Umgebungsvariablen: HOME, USER, PATH, PWD, $?. printf für formatierte Ausgabe. Heredoc <<EOF für mehrzeilige Strings. Arrays mit (), Zugriff per ${arr[i]}.
