Bash Guidelines¶
Write Bash scripts that are idiomatic, robust, and readable. ShellCheck compliance is mandatory — run in CI.
Setup¶
Every script starts with:
-e— exit immediately on error-u— treat unset variables as errors-o pipefail— propagate errors through pipes
Variables¶
- Quote all expansions:
"$VAR","${VAR}". - Use
readonlyfor constants:readonly MAX_RETRIES=3. - Use
localfor all variables inside functions.
Functions¶
- Extract reusable logic into named functions.
- Define functions before they are called.
- Use explicit
return <code>; never rely on the exit code of the last statement.
Error Handling¶
- Print errors to
stderr:echo "Error: ..." >&2. - Use
trapfor cleanup:trap cleanup EXIT. - Check required commands exist:
command -v docker >/dev/null || { echo "docker not found" >&2; exit 1; }.
Style¶
- Prefer
[[ ]]over[ ]for conditionals. - Prefer
printfoverechofor portability. - Use
$(command)for command substitution, not backticks.
Unix Philosophy¶
- Silent on success; errors to
stderr. - Exit
0on success; non-zero on failure. - Do one thing; compose with pipes.
Container Entrypoints¶
A container's debug runtime stage does not always carry bash. Check what the image ships, and pick the first shell that exists:
- bash, e.g. on
debian:<N>-slim:#!/usr/bin/env bashandset -euo pipefail, as above. - A POSIX shell only:
#!/usr/bin/env shandset -eu;pipefailis not POSIX. - BusyBox only, as in
distroless/*:debugand other BusyBox images:#!/busybox/sh,# shellcheck shell=shon the next line, andset -eu. These images have neither/bin/shnor/usr/bin/env, only/busybox/sh. ShellCheck does not recognize that shebang; the directive tells it to check the script as POSIXsh.
Directives¶
- Every script:
#!/usr/bin/env bash+set -euo pipefail; with a POSIX shell only:#!/usr/bin/env sh+set -eu; in a BusyBox image such asdistroless/*:debug:#!/busybox/sh+# shellcheck shell=sh+set -eu - Quote all expansions:
"$VAR","${VAR}"; usereadonlyfor constants;localinside functions - Extract reusable logic into named functions, defined before they're called
- Use explicit
return <code>in functions, never the last statement's exit code - Errors to stderr:
echo "Error: ..." >&2;trap cleanup EXITfor cleanup; check required commands exist before use - Prefer
[[ ]]over[ ],printfoverecho,$(command)over backticks - Silent on success; non-zero exit on failure; do one thing and compose via pipes