| name | bash-mastery |
| description | Shell scripting, Makefile conventions, and modern CLI tooling. Use when writing or reviewing shell scripts, creating or modifying Makefiles, or choosing CLI tools for automation tasks. |
| license | MIT |
Bash Mastery
Shell scripting, Makefile conventions, and modern CLI tooling.
When to Use
Scripting, Makefile, and CLI-tooling craft — not git plumbing (→ git-mastery)
and not the Bash-vs-dedicated-tool choice (→ tool-call-hygiene, which decides
whether to shell out at all versus use Read/Grep/Edit). Reach here once you've
decided a shell script is the right tool and need it to be correct and portable.
Bash Scripts
- Shebang:
#!/usr/bin/env bash
- Always use
set -euo pipefail.
- Implement
-h/--help with usage description.
- Prefer env vars over positional arguments; define/default at the top.
- Idempotency: multiple runs must produce the same state.
- Add brief comments to
if/elif/else branches.
Target bash 3.2, not the one on your PATH
macOS ships /bin/bash 3.2.57 (2007 — Apple froze it at the last GPLv2
release). A script that runs on your homebrew bash 5 can still be dead on
arrival for the user, and neither bash -n nor a test invoking bare bash
will tell you: both faults below passed the syntax check and ran clean on 5.
| Don't (bash 4+) | Do (3.2-safe) |
|---|
${v^} / ${v,,} case folding | tr '[:lower:]' '[:upper:]' |
declare -A map | parallel arrays, or a case |
mapfile -t a < f | while IFS= read -r l; do a+=("$l"); done |
${v@Q} | printf '%q' |
cmd &>> log | cmd >> log 2>&1 |
The empty-array trap. Under set -u, a bare "${arr[@]}" on an empty
array is a fatal unbound variable on 3.2 — and fine on 4.4+. Use one of:
"${arr[@]+"${arr[@]}"}"
"${arr[@]:-}"
[[ ${#arr[@]} -eq 0 ]] && return
Two of these shipped to users before the guard existed (HATS-1294, HATS-1352).
tests/e2e/test_library_shell_bash32_compat.py lints the table; hook tests
parametrize over every bash on the host, so 3.2 is actually executed.
Makefiles
Modern CLI Tooling
Prefer modern tools when available:
| Task | Use | Instead of |
|---|
| Search text | rg | grep |
| Find files | fd | find |
| View files | bat | cat |
| List dirs | eza | ls |
| JSON | jq | manual parsing |
| YAML | yq | manual parsing |
Fall back to traditional tools if modern ones are unavailable, but note the preference.
Anti-Patterns