Zum Inhalt springen
Bash Anfรคnger 20 min

Dein erstes Bash-Skript

Der Aufbau eines Bash-Skripts: Shebang, echo, Kommentare, Nutzereingabe und die Grundlagen von Variablen und Quoting.

Aktualisiert:
Inhaltsverzeichnis

Dein erstes Bash-Skript

Zeit, ein paar nuetzliche Skripte zu bauen. Wir starten klein und erweitern.

Hallo Welt

hallo.sh:

#!/usr/bin/env bash

echo "Hallo, Bash!"

Ausfuehrbar machen und starten:

chmod +x hallo.sh
./hallo.sh
# Hallo, Bash!

Der Shebang erklaert

#!/usr/bin/env bash
  • #! (Shebang) - sagt dem Kernel: โ€œInterpretiere die Datei mit folgendem Programmโ€
  • /usr/bin/env bash - sucht bash im PATH und startet es. Portabler als #!/bin/bash.

Ohne Shebang muesstest du immer bash hallo.sh aufrufen.

Kommentare

# Einzeiliger Kommentar

# Alles nach # bis Zeilenende wird ignoriert

Bash hat keinen mehrzeiligen Kommentar. Fuer groessere Bloecke nutzt man oft:

: '
Hier ein mehrzeiliger
"Kommentar" - technisch ein No-Op mit einem String
'

echo und printf

echo "Hallo, Bash!"
echo                   # leere Zeile
echo "mit Zeilenumbruch"
echo -n "ohne Zeilenumbruch"

Fuer formatierte Ausgabe ist printf besser:

printf 'Name: %s\n' "Anna"
printf 'Alter: %d\n' 28
printf '%-10s %s\n' 'Name:' 'Anna'     # linksbuendig, Breite 10

printf ist portabler und vorhersehbarer als echo. Fuer produktions-Skripte empfohlen.

Variablen

#!/usr/bin/env bash

name="Anna"
alter=28

echo "Name: $name"
echo "Alter: $alter"
echo "Hallo, $name!"

Regeln:

  • Kein Leerzeichen um =! name = "Anna" ist ein Fehler.
  • Gross-/Kleinschreibung ist signifikant
  • Konvention: snake_case fuer eigene, UPPER_CASE fuer Konstanten / Environment

Variablen-Expansion

name="Anna"

echo "Hallo, $name!"           # Hallo, Anna!
echo "Hallo, ${name}!"          # genauso, aber klarer
echo 'Hallo, $name!'            # Hallo, $name!  (single quotes!)

echo "Ordner: ${HOME}/projekte" # interpoliert $HOME

Merke:

  • "..." (double-quoted): Variablen und $( ) werden expandiert
  • '...' (single-quoted): nichts wird expandiert - literal
  • ${var}: eindeutige Syntax, wenn danach Buchstaben folgen

Kommando-Substitution

Ergebnis eines Befehls in eine Variable packen:

heute=$(date +%Y-%m-%d)
echo "Heute ist $heute"

nutzer=$(whoami)
echo "Hallo, $nutzer!"

Alternative (aelter): Backticks `...` - aber $(...) ist besser (verschachtelbar).

Nutzereingabe

#!/usr/bin/env bash

read -p "Wie heisst du? " name
echo "Hallo, $name!"
  • read var - liest eine Zeile in var
  • -p "Prompt" - zeigt einen Prompt

Zahlen einlesen

read -p "Dein Alter: " alter

if [[ "$alter" =~ ^[0-9]+$ ]]; then
  echo "Alter ist $alter"
else
  echo "Das war keine Zahl" >&2
  exit 1
fi

Das [[ "$alter" =~ ^[0-9]+$ ]] ist ein Regex-Match.

Mehrere Werte

read -p "Name und Alter: " name alter
echo "$name ist $alter"

Exit-Codes

Jeder Befehl liefert einen Exit-Code:

  • 0 = Erfolg
  • Alles andere = Fehler
echo "OK"
echo "Exit-Code des letzten Kommandos: $?"

Ein Skript kann selbst einen Exit-Code zurueckgeben:

if [[ ! -f daten.txt ]]; then
  echo "Datei fehlt" >&2
  exit 1
fi

# ... Hauptprogramm
exit 0

STDOUT und STDERR

echo "Info" >&1            # STDOUT (default)
echo "Fehler" >&2          # STDERR

Warum die Trennung? Damit du Ausgaben verschieden behandeln kannst:

./skript.sh > ausgabe.txt 2> fehler.txt
./skript.sh &> alles.txt        # beides in eine Datei

set -euo pipefail - die goldene Regel

Setze diese Zeile an den Anfang fast jedes Skripts:

#!/usr/bin/env bash
set -euo pipefail

Was tun die Flags?

  • -e: Bei Fehler sofort abbrechen (kein stilles Weiterlaufen)
  • -u: Nicht gesetzte Variable = Fehler (verhindert Tippfehler)
  • -o pipefail: Auch Fehler in der Mitte von Pipes erkennen

Ohne die Flags laufen Skripte oft weiter, auch wenn sie eigentlich scheitern - das verschleiert Bugs.

Ein kleines Beispielskript

begruessung.sh:

#!/usr/bin/env bash
set -euo pipefail

# Pruefen, ob ein Argument uebergeben wurde
if [[ $# -lt 1 ]]; then
  echo "Aufruf: $0 <name>" >&2
  exit 1
fi

name="$1"
heute=$(date +%A)

echo "Hallo, $name!"
echo "Heute ist $heute."
echo "Tipp: Heute waere ein guter Tag fuer eine Pause."

Ausfuehren:

./begruessung.sh Anna
# Hallo, Anna!
# Heute ist Donnerstag.
# Tipp: Heute waere ein guter Tag fuer eine Pause.

Was ist hier passiert?

  • $0 = Name des Skripts
  • $1 = erstes Argument
  • $# = Anzahl der Argumente
  • $(date +%A) = aktueller Wochentag (langer Name)

Kommandozeilenargumente

#!/usr/bin/env bash

echo "Skript: $0"
echo "Anzahl Args: $#"
echo "Alle Args: $@"
echo "Erstes: $1"
echo "Zweites: $2"

# Iteration
for arg in "$@"; do
  echo "  - $arg"
done

Immer "$@" (mit Quotes!) nutzen - das behandelt Leerzeichen in Argumenten korrekt.

Praktisches Beispiel: Backup-Skript

#!/usr/bin/env bash
set -euo pipefail

QUELLE="${1:-$HOME/projekte}"    # Default, wenn $1 fehlt
ZIEL_ORDNER="${HOME}/backups"
ZEITSTEMPEL=$(date +%Y%m%d-%H%M%S)
ZIEL="${ZIEL_ORDNER}/projekte-${ZEITSTEMPEL}.tar.gz"

if [[ ! -d "$QUELLE" ]]; then
  echo "Quelle nicht gefunden: $QUELLE" >&2
  exit 1
fi

mkdir -p "$ZIEL_ORDNER"

echo "Erstelle Backup..."
tar -czf "$ZIEL" "$QUELLE"

groesse=$(du -h "$ZIEL" | cut -f1)
echo "Fertig: $ZIEL ($groesse)"

Das ist ein echtes, nuetzliches Skript in ~20 Zeilen.

Zusammenfassung

  • #!/usr/bin/env bash + chmod +x = ausfuehrbares Skript
  • Variablen ohne Typ, kein Leerzeichen um =
  • "..." fuer Interpolation, '...' fuer literal
  • $(...) fuer Kommando-Substitution
  • read -p "..." fuer Eingabe, echo / printf fuer Ausgabe
  • STDERR mit >&2, Exit-Code mit exit N
  • set -euo pipefail fast immer am Anfang

Im naechsten Kapitel: Variablen, Parameter-Expansion und die Tricks, die Bash maechtig machen.

Zurรผck zum Bash Kurs