Skip to content
shellmap

dialogdialog TUI widgets — menus, inputbox, password, progress gauges from shell scripts. whiptail vs dialog vs newt. pwsh Read-Host + WPF alternatives across all 5 shells

Equivalents in every shell

Bashunix
dialog --inputbox "Enter your name:" 8 40 2>/tmp/result && name=$(cat /tmp/result)

Classic ncurses-based widget toolkit. Each widget exits with rc 0 (OK) / 1 (Cancel) / 255 (ESC), and writes the user's input to STDERR (not stdout — counter-intuitive but historical). Capture pattern: `dialog --inputbox "prompt" 8 40 2>/tmp/result`. Widget zoo: `--inputbox`, `--passwordbox` (no-echo), `--yesno` (rc only, no text), `--menu` (numbered choices), `--checklist`/`--radiolist`, `--msgbox` (display + dismiss), `--gauge` (progress bar fed from stdin: `for i in {1..100}; do echo $i; sleep 0.05; done | dialog --gauge "Loading..." 8 40 0`). Dimensions: `<height> <width>`. Set `DIALOGRC` env var for custom theme. Distro packages: `apt install dialog`, `dnf install dialog`, `pacman -S dialog`, `brew install dialog`.

Zshunix
dialog --inputbox "Enter your name:" 8 40 2>/tmp/result && name=$(cat /tmp/result)
Fishunix
dialog --inputbox "Enter your name:" 8 40 2>/tmp/result; and set name (cat /tmp/result)

fish does NOT have bash's `$(cmd)` substitution — use `(cmd)` braces instead, and `;` separator with `; and` for chaining (idiomatic) or `&&` (fish 3.0+ accepts both). For long-form: `dialog --inputbox "prompt" 8 40 2>/tmp/result; and set name (cat /tmp/result); rm /tmp/result`.

PowerShellwindows
$name = Read-Host "Enter your name"

pwsh has NO ncurses-style TUI primitive in core — the closest analogues: `Read-Host` (single-line input, no widget framing), `Out-GridView -PassThru` (table picker with Cancel/OK, more like a richer `--menu`), `[Microsoft.VisualBasic.Interaction]::InputBox()` (graphical input box via Add-Type + System.Windows.Forms — Windows-only). For multi-widget flows, the community module `PSWriteHTML` builds HTML reports; for TUI specifically, `PSMenu` (Out-Menu cmdlet) handles menus. CAVEAT: nothing in pwsh provides dialog's `--gauge` (live progress bar with no full-screen takeover) — `Write-Progress` is the equivalent for the pwsh status bar.

cmd.exewindows
set /p name="Enter your name: "

cmd has `set /p` for simple line-input. No TUI primitives. The `choice` builtin handles a single-character menu: `choice /C YN /M "Continue?"` (rc 1 = Y, rc 2 = N). For richer TUI on Windows: install Cygwin / MSYS2 / WSL to get `dialog` and `whiptail`. Or shell to `powershell -Command "Read-Host"` from cmd for parity with pwsh's input handling. Modern Microsoft also ships `winget` which uses its own TUI-style prompts but exposes no scripting hooks.

Worked examples

Simple input box

Bash
dialog --inputbox "Enter name:" 8 40 2>/tmp/result
Zsh
dialog --inputbox "Enter name:" 8 40 2>/tmp/result
PowerShell
$name = Read-Host "Enter name"
cmd.exe
set /p name="Enter name: "

Yes/No confirmation (returns exit code only)

Bash
dialog --yesno "Continue?" 7 40
Zsh
dialog --yesno "Continue?" 7 40
PowerShell
$resp = Read-Host "Continue? (y/n)"; if ($resp -eq "y") { ... }
cmd.exe
choice /C YN /M "Continue?"

Menu (numbered choices)

Bash
dialog --menu "Pick:" 12 40 4 1 "Option A" 2 "Option B" 3 "Option C" 2>/tmp/result
Zsh
dialog --menu "Pick:" 12 40 4 1 "Option A" 2 "Option B" 3 "Option C" 2>/tmp/result
PowerShell
"Option A","Option B","Option C" | Out-GridView -Title "Pick" -PassThru
cmd.exe
choice /C ABC /M "Pick: A,B,C"

Progress bar fed from a long-running task

Bash
(for i in 1 25 50 75 100; do echo $i; sleep 1; done) | dialog --gauge "Working..." 8 40 0
Zsh
(for i in 1 25 50 75 100; do echo $i; sleep 1; done) | dialog --gauge "Working..." 8 40 0
PowerShell
1..100 | ForEach-Object { Write-Progress "Working" -PercentComplete $_; Start-Sleep -Milliseconds 50 }
cmd.exe
powershell -Command "1..100 | ForEach-Object { Write-Progress Working -PercentComplete $_; Start-Sleep -Milliseconds 50 }"

Gotchas

  • **Result goes to STDERR, not stdout — by design but counter-intuitive.** Every `dialog` widget that captures input writes the user's answer to STDERR. stdout is reserved for the widget's curses-screen drawing (writes terminal escape codes during the interaction). So `result=$(dialog --inputbox ...)` returns the EMPTY STRING — the value lives in stderr. Canonical pattern: `dialog --inputbox "x" 8 40 2>/tmp/result; value=$(cat /tmp/result); rm /tmp/result`. Or redirect stderr to a process substitution: `value=$(dialog --inputbox "x" 8 40 3>&1 1>&2 2>&3)` — the descriptor-shuffle trick swaps fd 1 and fd 2 so the dialog answer comes out on stdout. The trick form is awkward but avoids the tempfile.
  • **`dialog` vs `whiptail` vs `newt` — three implementations, mostly compatible.** `dialog` (Savio Lam / Thomas Dickey lineage, 1990s+, full-featured) is the original. `whiptail` (from `newt`, RedHat lineage, used in Debian/Ubuntu installers) is a slimmer reimplementation with mostly-compatible CLI flags — Debian's installer uses whiptail. Most flags work identically: `--menu`, `--inputbox`, `--yesno`. Differences: whiptail does NOT support `--mixedform`, `--treeview`, `--editbox`; whiptail's `--gauge` is simpler. Detect at script start: `command -v dialog || command -v whiptail` and assign to a variable. For maximum portability across Debian (whiptail) + Arch (dialog) + macOS (brew dialog), write your script with the common subset.
  • **Tempfile cleanup and `trap` discipline.** The "write to stderr → tempfile" pattern leaks tempfiles if the script is interrupted. ALWAYS set up cleanup: `tmpfile=$(mktemp); trap "rm -f $tmpfile" EXIT INT TERM; dialog --inputbox "x" 8 40 2>"$tmpfile"; value=$(cat "$tmpfile")`. The `trap … EXIT INT TERM` ensures the tempfile is removed on normal exit, Ctrl-C, or kill. CAVEAT: don't use `/tmp/result` hardcoded across multiple concurrent script instances — they clobber each other. `mktemp` generates a unique path. macOS `mktemp` requires a template argument: `mktemp -t prefix` (older macOS); Linux `mktemp` works with no args (template defaults to `tmp.XXXXXX`).
  • **Sizing widgets is finicky — auto-size with `0 0`.** `dialog --inputbox "prompt" <height> <width>` — fixed dimensions, error if too small for the prompt text. Setting both to 0 auto-sizes to fit the content: `dialog --inputbox "Long prompt text that wraps naturally" 0 0`. For consistent UX across terminals (xterm, gnome-terminal, tmux at various sizes), prefer auto-size. The `--colors` flag enables embedded color codes in prompts (e.g. `\Zb` bold, `\Z1` red, `\Zn` reset) — useful for highlighting WARNING messages. Without `--colors`, the escape codes render as garbage.
  • **TUI vs CLI mode — non-interactive fallback for scripts.** `dialog` ONLY works on a terminal — running it in a pipe / cron / CI fails with `dialog: This program cannot use a non-interactive terminal`. For scripts that need to run both interactively AND headlessly: check `[ -t 0 ]` (is stdin a tty?) first and branch: `if [ -t 0 ] && command -v dialog >/dev/null; then dialog --inputbox …; else read -p "Enter name: " name; fi`. For CI: pass values via env vars / flags rather than prompting. The expect-pattern (the `/cmd/expect` sibling) can drive a dialog-based script from an automation harness if necessary — but cleaner to make the script accept env-var overrides.

WSL & PowerShell Core notes

pwshNo pwsh-native ncurses-style widget toolkit. For Windows-only graphical dialogs: `Add-Type -AssemblyName System.Windows.Forms; [System.Windows.Forms.MessageBox]::Show(...)`. For cross-platform pwsh TUI: install community module `PSMenu` (`Install-Module PSMenu`) — provides `Out-Menu` with checklist / radio / input semantics. For terminal styling, the `PSStyle` automatic variable (pwsh 7.2+) gives ANSI escape codes without external dependencies.
WSLWSL Linux `dialog` and `whiptail` work natively. To call FROM Windows-side: `wsl.exe dialog --inputbox "x" 8 40 2>/tmp/result` — output and TUI render in the Windows Terminal correctly under modern WSL2. Caveat: if running from a non-terminal context (PowerShell ISE, Out-GridView), the dialog draws garbled — invoke from a real terminal (Windows Terminal, ConEmu).

Related commands