Techniques I use to create a great user experience for shell scripts
Shell scripting for CLI tools is praised as powerful but riddled with footguns, prompting calls for better user experience through practices like robust error handling, careful use of `set -e`/`pipefail`, color output that respects TTY and `$NO_COLOR`, and consistent argument parsing and help text. Commenters share concrete patterns (spinners, logging functions, dependency checks, script directory detection, ShellCheck, style guides) while also warning about unsafe idioms (`rm -rf ${VAR}/*`, unquoted variables, fragile text parsing). A recurring theme is where to draw the line: many argue bash is ideal for simple “command glue,” but anything with complex logic, data structures, or long-term maintainability is better served by higher-level languages such as Python, Go, or PowerShell.
Spinner, Progress, and Output Styling
- Several commenters like simple spinners for long‑running scripts; progress bars are seen as harder because you often don’t know total work up front.
- Many advocate conditional color: only if stdout is a TTY,
NO_COLORis unset, and sometimesTERMisn’tdumb. Techniques:tput, cached escape sequences, or simple POSIX checks. - Others warn colors can make output unreadable with some themes and are unnecessary noise; some “typesetting” advice says avoid color entirely.
- Examples shared: tiny color helpers, an
awk-based “theme” filter, and TUI helpers like Glow/Gum (with some criticism of past network behavior).
Error Handling, set -e, pipefail, and Safety
- Strong push to avoid classic footguns: unquoted variables, missing
--, not checking emptiness beforerm -rf, and unsafe command detection. - Exit codes: several note that usage errors should conventionally use
exit 2, not1. - Heavy debate around
set -e/pipefail:- Pro side: good defaults that force fail‑fast behavior instead of silently continuing on errors.
- Con side: confusing semantics (e.g., functions used as predicates, pipelines) and hard‑to‑diagnose failures with little context; some prefer explicit
$?/PIPESTATUSchecks and guardrails instead.
- Examples show how
set -e -o pipefailcan terminate scripts mid‑pipeline without clearly indicating where or why.
Linters, Style, and Boilerplate
- Many recommend ShellCheck as essential for catching shell footguns; others find it noisy or wrong in places and prefer to rely on experience, treating it as an optional “typed subset” of shell.
- Google’s shell style guide and frameworks like bash3boilerplate and bash‑modules are cited for consistent logging, argument parsing, and error handling.
- Some advocate structured argument specs that auto‑generate help and parsing.
Shell vs. Other Languages / PowerShell Debate
- Recurring view: shell is ideal for “command glue” and pipelines; once you need complex logic, data structures, math, or concurrency, switch to Python, Go, Rust, etc.
- Others highlight bash’s portability and longevity vs. dependency and version churn in Python or other runtimes.
- Length thresholds vary: some say anything over ~50 lines shouldn’t be shell, others are comfortable into hundreds or more.
- Big sub‑thread contrasts Unix text pipelines with PowerShell’s object pipelines; proponents praise PowerShell’s typing, parameter validation, and tooling; critics cite performance, complexity, Windows‑centricity, and niche ecosystem.
Misc UX Tips
- Suggestions include: robust OS/command detection, better help handling (
-h/--helpand interactive prompts when args are missing), clear logging with levels,isattychecks, and usingsh -xorset -xfor debugging.