gum und whiptail: TUI-Menüs für Bash-Skripte bauen
AI generated
$_
#!/
Bash · gum · whiptail · TUI
gum und whiptail: TUI-Menüs für Bash-Skripte bauen
von der Nummernabfrage zum echten Terminal-Dialog

gum und whiptail verwandeln ein Bash-Skript in eine Anwendung mit echten Rahmen, Formularen und Bestätigungsdialogen, ohne dass eine grafische Oberfläche nötig ist. Dieser Artikel zeigt, wie beide Werkzeuge in eigenen Skripten eingesetzt werden, wo sie sich unterscheiden und wann sich der Einsatz gegenüber einfacheren Bash-Bordmitteln lohnt.

19 Min. Lesezeit gum · whiptail · Formulare · Styling Bash 4.x · 5.x · Linux · macOS

1. Warum TUI-Menüs mehr sind als Zuckerguss

Ein TUI-Menü, gebaut mit gum oder whiptail, unterscheidet sich von einem einfachen echo-Menü nicht nur optisch. Rahmen, farbige Hervorhebungen und klar abgegrenzte Dialogfenster geben dem Anwender sofortiges visuelles Feedback darüber, welcher Teil des Bildschirms zur aktuellen Eingabeaufforderung gehört. Bei komplexeren Wartungsskripten mit mehreren aufeinanderfolgenden Abfragen reduziert das Bedienfehler erheblich, weil unklare Zustände seltener entstehen.

Der zweite Vorteil ist die eingebaute Validierung von Formularfeldern und Bestätigungsdialogen. Statt eigene read-Schleifen mit manueller Eingabeprüfung zu schreiben, liefern gum und whiptail fertige Bausteine für Ja/Nein-Abfragen, Texteingaben, Auswahllisten und Checkboxen. Für Admin-Skripte, die von mehreren Personen im Team genutzt werden, macht ein konsistentes TUI-Menü-Layout den Unterschied zwischen einem Werkzeug, dem man vertraut, und einem, das man lieber meidet.

2. whiptail: Dialoge aus dem Systempaket

whiptail ist auf den meisten Debian- und Ubuntu-Systemen bereits vorinstalliert, weil es intern vom Installer verwendet wird. Das macht es zur pragmatischsten Wahl für Skripte, die ohne zusätzliche Installation auskommen müssen. Die Syntax orientiert sich am älteren dialog-Programm: Jeder Dialogtyp wird über einen Parameter wie --yesno, --inputbox oder --menu ausgewählt, gefolgt von Titel, Text und Größenangaben in Zeilen und Spalten.

Das Ergebnis eines whiptail-Dialogs wird nicht über stdout, sondern über stderr zurückgegeben, was für viele Neueinsteiger überraschend ist. Der Exit-Code signalisiert, ob der Anwender bestätigt (0) oder abgebrochen hat (1), während der eigentliche Eingabewert mit 3>&1 1>&2 2>&3 aus stderr in eine Variable umgeleitet werden muss. Dieses Umleitungs-Pattern ist die Grundlage jeder whiptail-Integration in Bash und sollte einmal verstanden werden, statt bei jedem neuen Skript neu nachgeschlagen zu werden.


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

if ! command -v whiptail &>/dev/null; then
  echo "[ERROR] whiptail nicht gefunden" >&2
  exit 1
fi

# yesno dialog — exit code signals the choice, no stdout redirection needed
if whiptail --title "Deployment bestaetigen" \
    --yesno "Nach production deployen?" 10 50; then
  echo "Bestaetigt, starte Deployment..."
else
  echo "Abgebrochen." >&2
  exit 1
fi

# inputbox dialog — result comes from stderr, redirected into a variable
target=$(whiptail --title "Zielverzeichnis" \
  --inputbox "Wohin soll deployed werden?" 10 50 "/var/www/html" \
  3>&1 1>&2 2>&3)

echo "Zielverzeichnis: $target"

3. whiptail-Formulare: mehrere Eingaben in einem Dialog

Ein einzelnes --inputbox reicht für einfache Abfragen, aber viele Wartungsskripte brauchen mehrere Werte gleichzeitig, etwa Hostname, Port und Benutzername für eine Datenbankverbindung. whiptail bietet dafür --menu für Auswahllisten und --checklist für Mehrfachauswahl mit Checkboxen. Beide geben die gewählten Tags getrennt durch Leerzeichen zurück, die anschließend mit read -ra in ein Array zerlegt werden sollten, statt sie als einzelnen String weiterzuverarbeiten.

Ein --checklist-Dialog eignet sich hervorragend für Skripte, die optionale Schritte anbieten, etwa welche Backup-Komponenten in einem Lauf enthalten sein sollen. Die Tags in eckigen Klammern nach jedem Listeneintrag steuern, ob eine Option standardmäßig aktiviert ist. Dieses Muster ersetzt mehrere aufeinanderfolgende read -p "Ja/Nein"-Abfragen durch einen einzigen übersichtlichen Dialog, den der Anwender in einem Durchgang bearbeitet.


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

# checklist: multiple optional steps in a single dialog
choices=$(whiptail --title "Backup-Komponenten" \
  --checklist "Was soll gesichert werden?" 15 60 5 \
  "db" "Datenbank" ON \
  "media" "Medien-Dateien" ON \
  "config" "Konfigurationsdateien" OFF \
  "logs" "Log-Dateien" OFF \
  3>&1 1>&2 2>&3)

# whiptail returns quoted tags separated by spaces — parse into an array
read -ra selected_components <<< "${choices//\"/}"

echo "Sichere: ${selected_components[*]}"
for component in "${selected_components[@]}"; do
  echo "  -> Verarbeite $component"
done

4. gum: modernes Styling ohne dialog-Syntax

gum von Charmbracelet verfolgt einen anderen Ansatz als whiptail: Statt eines einzelnen Programms mit vielen Parametern liefert gum mehrere Unterbefehle wie gum choose, gum input, gum confirm und gum spin, die sich wie eigenständige Unix-Werkzeuge in Pipes einsetzen lassen. Das Ergebnis landet direkt auf stdout, ohne die Umleitungs-Akrobatik, die whiptail erfordert.

Der zweite große Unterschied liegt im Erscheinungsbild: gum nutzt standardmäßig abgerundete Rahmen, Farbverläufe und eine moderne Typografie, die sich näher an aktuellen CLI-Werkzeugen orientiert als am klassischen dialog-Look von whiptail. Für Teams, die ihre internen Tools optisch aufwerten möchten, ist gum oft die bevorzugte Wahl, muss allerdings separat installiert werden, da es nicht in Standard-Distributionen enthalten ist.


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

if ! command -v gum &>/dev/null; then
  echo "[ERROR] gum nicht gefunden, siehe https://github.com/charmbracelet/gum" >&2
  exit 1
fi

# gum choose — result goes straight to stdout, no redirection needed
environment=$(gum choose "staging" "production" "canary" --header "Umgebung waehlen")

# gum confirm — clean boolean via exit code
if gum confirm "Wirklich nach $environment deployen?"; then
  name=$(gum input --placeholder "Dein Name" --prompt "Freigabe durch: ")
  echo "Deployment nach $environment freigegeben von $name"
else
  echo "Abgebrochen." >&2
  exit 1
fi

5. gum in einem kompletten Deployment-Workflow

Der eigentliche Nutzen von gum zeigt sich, wenn mehrere Unterbefehle zu einem zusammenhängenden Workflow kombiniert werden. Ein typisches Beispiel: Zuerst wählt der Anwender mit gum choose die Zielumgebung, dann bestätigt er mit gum confirm, anschließend läuft der eigentliche Deployment-Befehl gekapselt in gum spin, das während der Ausführung einen Ladeindikator anzeigt und danach automatisch verschwindet.

Diese Kombination aus Auswahl, Bestätigung und visuellem Feedback während der Ausführung macht ein Skript spürbar hochwertiger, ohne dass eigener Code für Spinner oder Fortschrittsanzeige geschrieben werden muss. gum spin übernimmt genau diese Aufgabe und beendet sich automatisch, sobald der übergebene Befehl fertig ist, inklusive der Weitergabe des Exit-Codes an das aufrufende Skript.


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

env=$(gum choose "staging" "production" --header "Zielumgebung")

gum confirm "Nach $env deployen?" || { echo "Abgebrochen."; exit 1; }

# gum spin wraps a long-running command with a loading indicator
gum spin --spinner dot --title "Deploye nach $env..." -- \
  bash -c "sleep 3 && echo Deployment abgeschlossen"

echo "Fertig."

6. Eigenes Styling: Farben, Rahmen und Breiten anpassen

Sowohl gum als auch whiptail erlauben eigenes Styling, allerdings auf unterschiedliche Weise. Bei whiptail ist die Anpassung begrenzt: Farben lassen sich nur über Umgebungsvariablen wie NEWT_COLORS beeinflussen, was wenig dokumentiert und entsprechend fehleranfällig ist. gum hingegen bietet für fast jeden Unterbefehl eigene Flags wie --border rounded, --border-foreground oder --width, die direkt in der Kommandozeile gesetzt werden.

Für Skripte, die als internes Firmenwerkzeug mehrfach genutzt werden, lohnt sich eine kleine Wrapper-Funktion, die die Styling-Parameter zentral definiert. So bleibt das optische Erscheinungsbild über alle Skripte hinweg konsistent, und Änderungen am Corporate-Look müssen nur an einer Stelle gepflegt werden, statt in jedem einzelnen Skript wiederholt zu werden.

7. Fehlerbehandlung und Exit-Codes bei Abbruch

Beide Werkzeuge signalisieren einen Abbruch durch den Anwender über einen Nicht-Null-Exit-Code, allerdings mit unterschiedlichen Zahlenwerten je nach Dialogtyp. Bei whiptail steht Exit-Code 1 in der Regel für "Cancel" oder "No", während Exit-Code 255 einen Abbruch durch Esc signalisiert, was bei genauerer Fehlerbehandlung explizit unterschieden werden sollte. gum vereinfacht das: Sowohl Abbruch mit Esc als auch eine explizite Ablehnung liefern einen Nicht-Null-Code, sodass ein einfaches || exit 1 in den meisten Fällen ausreicht.

Wichtig ist, dass set -e bei beiden Werkzeugen dieselben Effekte hat wie bei fzf: Ein abgebrochener Dialog beendet das Skript sofort, wenn keine explizite Behandlung erfolgt. Für Skripte mit mehreren aufeinanderfolgenden Dialogen empfiehlt sich eine zentrale Funktion, die bei jedem Abbruch eine einheitliche Meldung ausgibt und das Skript kontrolliert beendet, statt an verschiedenen Stellen unterschiedlich zu reagieren.

8. Portabilität: Installation prüfen und Fallback bauen

Weder gum noch whiptail sind auf jedem System garantiert vorhanden. whiptail fehlt typischerweise auf minimalen Alpine-Images oder reinen Server-Distributionen ohne den Installer-Unterbau, gum muss praktisch überall explizit über Paketmanager oder Go-Install nachinstalliert werden. Ein produktionsreifes Skript prüft beide Abhängigkeiten am Anfang und liefert eine klare Fehlermeldung mit Installationshinweis, statt mitten im Ablauf mit "command not found" abzubrechen.

Für maximale Portabilität kann ein Skript zusätzlich eine Kaskade aus mehreren Werkzeugen implementieren: zuerst gum versuchen, dann auf whiptail zurückfallen, zuletzt auf reines read. Diese dreistufige Fallback-Kette ist aufwendiger zu pflegen, garantiert aber, dass ein Skript in jeder Umgebung lauffähig bleibt, unabhängig davon, welche Zusatzwerkzeuge installiert sind.


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

confirm_action() {
  local message="$1"

  if command -v gum &>/dev/null; then
    gum confirm "$message"
  elif command -v whiptail &>/dev/null; then
    whiptail --yesno "$message" 10 50
  else
    read -rp "$message [y/N] " reply
    [[ "$reply" =~ ^[Yy]$ ]]
  fi
}

if confirm_action "Wirklich fortfahren?"; then
  echo "Fortfahren."
else
  echo "Abgebrochen." >&2
  exit 1
fi

9. gum, whiptail und dialog im Vergleich

Die Wahl zwischen gum, whiptail und dem klassischen dialog-Programm hängt vom Zielsystem und den optischen Ansprüchen ab. Alle drei lösen dasselbe Grundproblem, unterscheiden sich aber deutlich in Verfügbarkeit und Bedienkomfort.

Werkzeug Vorinstalliert stdout-Ausgabe Optisches Styling
gum Nein Direkt auf stdout Modern, konfigurierbar
whiptail Meist ja (Debian/Ubuntu) Nur via stderr-Umleitung Klassisch, begrenzt
dialog Teilweise Nur via stderr-Umleitung Klassisch, begrenzt
read -p / select Immer (Bash-Builtin) Direkt Keins

In der Praxis entscheidet oft die Zielumgebung: Für Skripte, die auf beliebigen Servern laufen müssen, ist whiptail wegen der breiten Vorinstallation die sicherere Wahl. Für interne Entwickler-Tools, bei denen das Team die Installation von gum kontrolliert, überzeugt der modernere Look und die einfachere stdout-Integration. Beide Werkzeuge schließen sich nicht aus und lassen sich, wie im Fallback-Beispiel gezeigt, in derselben Codebasis kombinieren.

Mironsoft

Shell-Automatisierung und CLI-Tooling für Entwicklerteams

Interne Skripte, die sich wie echte Tools anfühlen?

Wir bauen TUI-Menüs mit gum oder whiptail für eure Wartungsskripte, mit Formularen, Bestätigungsdialogen und robusten Fallbacks für jede Zielumgebung.

TUI-Entwicklung

Formulare, Menüs und Bestätigungsdialoge mit gum oder whiptail bauen

Fallback-Ketten

Robuste Skripte, die auf jeder Zielumgebung ohne Zusatzinstallation laufen

Styling-Konsistenz

Einheitliches Erscheinungsbild über alle internen Wartungsskripte hinweg

10. Zusammenfassung

gum und whiptail lösen dasselbe Grundproblem auf unterschiedliche Weise: Aus einem Skript mit reinem Text-Output wird eine Anwendung mit echten Dialogfenstern, Formularen und Bestätigungen. whiptail punktet durch breite Vorinstallation und ist die pragmatische Wahl für Skripte, die auf beliebigen Servern laufen sollen. gum überzeugt durch modernes Styling, einfache stdout-Integration und eine intuitivere Kommandozeilen-Syntax, verlangt aber eine separate Installation.

In der Praxis lohnt sich für viele Teams eine pragmatische Kombination: gum für interne Entwickler-Tools mit kontrollierter Umgebung, whiptail für Skripte auf fremden oder minimal ausgestatteten Servern, und ein einfacher read-Fallback für den Fall, dass keines von beiden verfügbar ist. Diese dreistufige Strategie stellt sicher, dass ein Skript überall lauffähig bleibt, während es dort, wo möglich, den bestmöglichen Bedienkomfort bietet.

gum und whiptail — Das Wichtigste auf einen Blick

whiptail-Grundmuster

Ergebnis via 3>&1 1>&2 2>&3 aus stderr in eine Variable umleiten, Exit-Code prüft Bestätigung.

gum-Grundmuster

Unterbefehle wie gum choose, gum confirm liefern Ergebnisse direkt auf stdout, keine Umleitung nötig.

Formulare

--checklist bei whiptail für Mehrfachauswahl, Ergebnis mit read -ra in ein Array parsen.

Portabilität

Verfügbarkeit mit command -v prüfen, dreistufige Fallback-Kette gum, whiptail, read einsetzen.

11. FAQ: gum und whiptail in Bash-Skripten

1Unterschied gum vs. whiptail?
whiptail meist vorinstalliert, Ergebnis via stderr. gum separat installiert, moderner, Ergebnis direkt auf stdout.
2Warum stderr bei whiptail?
Historisches Erbe von dialog. Mit 3>&1 1>&2 2>&3 lässt sich der Wert sauber in eine Variable umleiten.
3Mehrfachauswahl mit whiptail?
--checklist mit Tag, Beschreibung, ON/OFF pro Eintrag. Ergebnis mit read -ra in ein Array parsen.
4gum vorinstalliert?
Nein, immer separat installieren. Mit command -v gum prüfen und Fallback bereitstellen.
5Ladeindikator mit gum?
gum spin --title 'Text' -- befehl. Läuft mit, beendet sich automatisch, gibt Exit-Code weiter.
6Esc-Abbruch bei whiptail erkennen?
Meist Exit-Code 255 bei Esc, 1 bei No/Cancel. Genauen Code prüfen für differenzierte Behandlung.
7gum und whiptail kombinieren?
Ja, mit command -v erst gum prüfen, dann whiptail, zuletzt read als Fallback-Kette.
8Farben in whiptail stylen?
Über NEWT_COLORS, begrenzt und schlecht dokumentiert im Vergleich zu gums direkten Styling-Flags.
9Besser für fremde Server?
whiptail, wegen breiter Vorinstallation auf Debian/Ubuntu. gum eher für interne, kontrollierte Umgebungen.
10set -e Besonderheiten?
Abgebrochener Dialog erzeugt Nicht-Null-Exit-Code, beendet Skript sofort ohne explizite Behandlung mit || oder if.