Anleitung

Bash-Skript für Einsteiger: erstes Skript, Variablen, Bedingungen, Schleifen und cron

Aktualisiert: · Skillaria.Top

Ein Bash-Skript ist eine Textdatei mit Shell-Befehlen, die mit der Zeile #!/bin/bash beginnt, per chmod +x das Ausführungsrecht erhält und als ./skript.sh gestartet wird. Skripte nutzen Variablen, die Argumente $1 und $2, if-Bedingungen, for- und while-Schleifen; regelmäßige Ausführung richten Sie mit crontab -e ein.

Ein Bash-Skript ist eine einfache Textdatei mit Befehlen, die Sie sonst einzeln im Terminal eintippen würden. Das Skript beginnt mit der Shebang-Zeile #!/bin/bash, erhält per chmod +x das Ausführungsrecht und wird als ./skript.sh gestartet. Diese Anleitung für Einsteiger führt Sie von der ersten Zeile bis zur zeitgesteuerten Ausführung: Variablen, Argumente, Bedingungen, Schleifen, Fehlerbehandlung und cron.

Das erste Bash-Skript in einer Minute

Legen Sie eine Datei in einem beliebigen Editor an, zum Beispiel nano:

nano hallo.sh
#!/bin/bash
# Erstes Skript: Begrüßung und ein paar Systeminformationen
echo "Hallo, $USER!"
echo "Heute: $(date +%Y-%m-%d)"
echo "Sie befinden sich in: $(pwd)"

Speichern Sie (Strg+O, Enter, Strg+X), geben Sie das Ausführungsrecht und starten Sie das Skript:

$ chmod +x hallo.sh
$ ./hallo.sh
Hallo, alice!
Heute: 2026-10-12
Sie befinden sich in: /home/alice

Zeilen, die mit # beginnen, sind Kommentare. $(befehl) fügt die Ausgabe eines Befehls direkt in die Zeile ein.

Shebang: wozu die erste Zeile dient

Die Zeile #!/bin/bash sagt dem System, mit welchem Interpreter die Datei ausgeführt werden soll. Ohne sie läuft das Skript in der Shell, die gerade verfügbar ist; auf manchen Systemen ist /bin/sh nicht bash, sondern das einfachere dash, wo einige Konstrukte nicht funktionieren.

Häufig begegnet man auch #!/usr/bin/env bash: Es sucht bash im PATH, was praktisch ist, wenn bash nicht in /bin installiert ist.

Wie man ein Skript startet und warum ./

Es gibt zwei Wege:

  • ./hallo.sh — braucht Shebang und das Recht x. Das Präfix ./ ist Pflicht, weil das aktuelle Verzeichnis nicht im PATH steht.
  • bash hallo.sh — kein Ausführungsrecht nötig, der Interpreter wird ausdrücklich angegeben.

Sehen Sie command not found ohne ./ oder Permission denied ohne chmod +x, sind genau das die beiden Ursachen. Damit Sie Ihre Skripte von überall per Namen aufrufen können, legen Sie sie in ~/bin oder /usr/local/bin.

Variablen

Eine Variable wird ohne Leerzeichen um das = zugewiesen und mit $ gelesen:

#!/bin/bash
name="backup"
verzeichnis="/var/backups"
heute=$(date +%F)

echo "Datei: ${verzeichnis}/${name}-${heute}.tar.gz"

Geschweifte Klammern trennen den Variablennamen vom umgebenden Text. Die Zeile name = "backup" mit Leerzeichen ist ein Fehler: bash versucht dann, einen Befehl namens name auszuführen.

Anführungszeichen sind wichtig

In doppelten Anführungszeichen werden Variablen ersetzt, in einfachen nicht. Variablen sollte man fast immer in doppelte Anführungszeichen setzen, sonst wird ein Dateiname mit Leerzeichen in zwei Argumente zerlegt.

datei="mein bericht.txt"
rm $datei      # Fehler: versucht „mein“ und „bericht.txt“ zu löschen
rm "$datei"    # richtig
echo '$HOME'   # gibt wörtlich $HOME aus
echo "$HOME"   # gibt /home/alice aus

Umgebungsvariablen

Variablen wie $HOME, $USER und $PATH setzt das System. Eine eigene Variable reichen Sie mit export an Kindprozesse weiter. Dauerhafte Einstellungen der Umgebung gehören in ~/.bashrc oder ~/.profile.

Argumente des Skripts

Werte, die beim Start übergeben werden, stehen als $1, $2 usw. zur Verfügung.

VariableWas sie enthält
$0der Name des Skripts
$1, $2…das erste, zweite Argument
$#die Anzahl der Argumente
"$@"alle Argumente, jedes einzeln
$?Exitcode des letzten Befehls
$$PID des aktuellen Skripts
#!/bin/bash
echo "Skript $0 hat $# Argument(e) erhalten"
echo "Erstes: $1"
$ ./argumente.sh nginx 80
Skript ./argumente.sh hat 2 Argument(e) erhalten
Erstes: nginx

Eine Eingabe des Benutzers liest der Befehl read: read -p "Name eingeben: " name.

if-Bedingungen

Jeder Befehl liefert einen Exitcode: 0 bedeutet Erfolg, alles andere einen Fehler. Die Konstruktion if prüft genau diesen Code. Für Vergleiche verwendet man [[ ... ]]; die Leerzeichen innerhalb der Klammern sind Pflicht.

#!/bin/bash
if [[ $# -eq 0 ]]; then
    echo "Verwendung: $0 <verzeichnis>"
    exit 1
fi

if [[ -d "$1" ]]; then
    echo "Verzeichnis $1 existiert"
elif [[ -f "$1" ]]; then
    echo "$1 ist eine Datei, kein Verzeichnis"
else
    echo "$1 nicht gefunden"
fi
PrüfungBedeutung
-f dateieine gewöhnliche Datei existiert
-d verzeichnisein Verzeichnis existiert
-e pfadder Pfad existiert
-x dateidie Datei ist ausführbar
-z "$var" / -n "$var"die Zeichenkette ist leer / nicht leer
"$a" == "$b", !=Zeichenkettenvergleich
-eq -ne -lt -le -gt -geZahlenvergleich

Sie können auch jeden Befehl direkt prüfen:

if systemctl is-active --quiet nginx; then
    echo "nginx läuft"
else
    echo "nginx ist gestoppt"
fi

Bei vielen Varianten ist case bequem:

case "$1" in
    start)   echo "Starte" ;;
    stop)    echo "Stoppe" ;;
    *)       echo "Unbekannter Befehl: $1"; exit 1 ;;
esac

for- und while-Schleifen

for: über eine Liste iterieren

for host in web1 web2 db1; do
    echo "Prüfe $host"
    ping -c 1 -W 1 "$host" > /dev/null && echo "  erreichbar" || echo "  nicht erreichbar"
done

for datei in /var/log/*.log; do
    echo "$datei: $(wc -l < "$datei") Zeilen"
done

for i in {1..5}; do
    echo "Versuch $i"
done

while: solange die Bedingung gilt

Ein klassisches Beispiel ist das zeilenweise Lesen einer Datei:

while read -r benutzer; do
    echo "Benutzer: $benutzer"
done < benutzer.txt

Und das Warten, bis ein Dienst hochgefahren ist:

zaehler=0
until curl -sf http://localhost:8080/health > /dev/null; do
    zaehler=$((zaehler + 1))
    if [[ $zaehler -ge 10 ]]; then
        echo "Dienst ist nicht gestartet"
        exit 1
    fi
    sleep 3
done
echo "Dienst ist bereit"

Arithmetik schreibt man in bash in doppelten Klammern: $((a + b)). Sie funktioniert nur mit ganzen Zahlen.

Funktionen

Wiederkehrenden Code lagert man in Funktionen aus. Innerhalb einer Funktion sind die Argumente dieselben $1, $2, und local verhindert, dass eine Variable nach außen dringt.

protokoll() {
    local stufe="$1"; shift
    echo "$(date '+%F %T') [$stufe] $*"
}

protokoll INFO "Starte die Sicherung"
protokoll ERROR "Kein Speicherplatz mehr"

Fehlerbehandlung: set -euo pipefail

Standardmäßig setzt bash nach einem fehlgeschlagenen Befehl fort — so kann ein Sicherungsskript „erfolgreich“ enden, ohne etwas kopiert zu haben. Am Anfang von Skripten setzt man daher oft den strikten Modus:

#!/bin/bash
set -euo pipefail
  • -e — beim ersten Fehler anhalten.
  • -u — die Verwendung einer nicht gesetzten Variable als Fehler behandeln (schützt vor rm -rf "$DIR/" mit leerem DIR).
  • -o pipefail — eine Pipeline gilt als fehlgeschlagen, wenn irgendein Teil scheitert.

Zum Debuggen starten Sie das Skript mit bash -x skript.sh: bash gibt jeden Befehl vor seiner Ausführung aus. Typische Fehler findet man vor dem Start mit dem Werkzeug shellcheck.

Praxisbeispiel: ein Sicherungsskript

#!/bin/bash
set -euo pipefail

QUELLE="${1:-/var/www}"
ZIEL="/var/backups/site"
AUFBEWAHRUNG_TAGE=7
ZEITSTEMPEL=$(date +%F_%H-%M)

mkdir -p "$ZIEL"
tar -czf "$ZIEL/site-$ZEITSTEMPEL.tar.gz" -C "$(dirname "$QUELLE")" "$(basename "$QUELLE")"
echo "Archiv erstellt: $ZIEL/site-$ZEITSTEMPEL.tar.gz"

# Archive löschen, die älter als AUFBEWAHRUNG_TAGE Tage sind
find "$ZIEL" -name "site-*.tar.gz" -mtime +"$AUFBEWAHRUNG_TAGE" -delete

Die Schreibweise ${1:-/var/www} bedeutet „das erste Argument, und falls keines da ist, /var/www“. Speichern Sie das Skript als /usr/local/bin/backup-site.sh und machen Sie es ausführbar: sudo chmod +x /usr/local/bin/backup-site.sh.

Regelmäßige Ausführung: cron

Cron ist der Dienst, der Befehle nach Zeitplan startet. Die Aufgaben eines Benutzers bearbeiten Sie mit crontab -e, anzeigen lassen sie sich mit crontab -l, die Aufgaben von root mit sudo crontab -e.

Eine Aufgabenzeile besteht aus fünf Zeitfeldern und dem Befehl:

# Minute Stunde Tag_im_Monat Monat Wochentag Befehl
30 2 * * * /usr/local/bin/backup-site.sh >> /var/log/backup.log 2>&1
ZeitplanWann er läuft
*/5 * * * *alle 5 Minuten
0 * * * *zu Beginn jeder Stunde
30 2 * * *jeden Tag um 02:30
0 9 * * 1-5werktags um 09:00
0 3 1 * *am 1. jedes Monats um 03:00
@rebooteinmal nach dem Systemstart

Warum ein Skript von Hand funktioniert, in cron aber nicht

  • Andere Umgebung. Cron startet Aufgaben mit einem minimalen PATH und ohne Ihre ~/.bashrc. Schreiben Sie vollständige Pfade zu Befehlen und Dateien oder setzen Sie PATH am Anfang der Crontab.
  • Anderes aktuelles Verzeichnis. Eine Aufgabe startet im Home-Verzeichnis, nicht dort, wo das Skript liegt. Verwenden Sie absolute Pfade.
  • Das Zeichen %. In einer Crontab bedeutet % einen Zeilenumbruch, deshalb muss date +%F direkt in der Aufgabenzeile als \% geschrieben werden. Einfacher ist es, den Befehl in ein Skript auszulagern.
  • Die Ausgabe geht verloren. Leiten Sie die Ausgabe in ein Protokoll um (>> datei 2>&1), sonst sehen Sie die Fehler nicht. Cron-Läufe erscheinen in journalctl -u cron (auf RHEL-artigen Systemen heißt der Dienst crond).

Auf Systemen mit systemd sind Timer eine Alternative zu cron: Sie schreiben die Ausgabe ins Journal und können verpasste Läufe nachholen.

Fazit

Ein Bash-Skript für Einsteiger ist eine Datei mit der Shebang-Zeile #!/bin/bash, dem Ausführungsrecht und einer Folge von Befehlen. Ergänzen Sie Variablen in Anführungszeichen, eine Argumentprüfung mit if, die Schleifen for und while sowie den strikten Modus set -euo pipefail — und Sie haben ein zuverlässiges Automatisierungswerkzeug, das cron nach Zeitplan ausführen kann. Bash-Skripte, Umgebung und cron behandelt unser Linux-Kurs praxisnah Schritt für Schritt.

Häufige Fragen

Was ist der Unterschied zwischen bash und sh?

sh ist die standardisierte POSIX-Shell, bash ist deren erweiterte Version mit Arrays, doppelten Klammern und weiteren Komfortfunktionen. Ein Skript mit bash-Konstrukten muss mit bash gestartet werden, nicht mit sh.

Welche Dateiendung soll ein Bash-Skript haben?

Linux achtet nicht auf die Endung: Der Interpreter wird durch die Shebang-Zeile bestimmt. Die Endung .sh ist nur eine Konvention, damit Menschen erkennen, dass es ein Skript ist.

Wie übergebe ich ein Passwort sicher an ein Skript?

Übergeben Sie es nicht als Argument — Argumente sind für andere Benutzer in ps sichtbar. Verwenden Sie eine Umgebungsvariable aus einer Datei mit den Rechten 600 oder read -s für eine Eingabe ohne Anzeige.

Wie prüfe ich, ob das Skript als root läuft?

Vergleichen Sie die Benutzer-ID mit null: if [[ $EUID -ne 0 ]]; then echo "root ist erforderlich"; exit 1; fi.

Wie starte ich ein Skript im Hintergrund, damit es nach dem Abmelden von SSH weiterläuft?

Verwenden Sie nohup ./skript.sh &, eine tmux- oder screen-Sitzung, und für den Dauerbetrieb verpacken Sie das Skript in einen systemd-Dienst.

Das Thema im Video lernen

Dieses Thema wird im Kurs „Linux: с нуля до уверенного администрирования“ ausführlich mit Praxis behandelt.

Zum Kurs