Part 3 · 1 chapters · ~8 min
Shell Scripting Properly
Strict mode (set -euo pipefail) and its caveats, quoting and word splitting, arrays, parameter expansion and defaults, conditionals and [[ ]], functions and local variables, traps and cleanup, temporary files, argument parsing, shellcheck in CI, portability (bash versus POSIX sh versus zsh), and when to switch to a real language.
4
A script template
code
#!/usr/bin/env bash
set -euo pipefail
IFS=$'\n\t'
usage() { echo "usage: $0 -e <env> <release-tag>" >&2; exit 2; }
env=""; while getopts "e:" opt; do case $opt in e) env=$OPTARG ;; *) usage ;; esac; done
shift $((OPTIND - 1)); tag=${1:?release tag required}
[[ $env =~ ^(staging|production)$ ]] || usage
tmp=$(mktemp -d); trap 'rm -rf "$tmp"' EXIT # always clean up, even on error
files=( "$tmp"/*.json ) # arrays, not word-split strings
log() { printf '%s %s\n' "$(date -u +%FT%TZ)" "$*" >&2; }
log "deploying $tag to $env"
curl -fsS "https://releases.example.com/$tag/manifest.json" -o "$tmp/manifest.json" # -f: fail on HTTP errors
jq -e '.digest' "$tmp/manifest.json" > /dev/null # -e: non-zero exit if missing
# shellcheck deploy.sh → run in CICaveat: set -e does not trigger inside if conditions, in commands joined with && or ||, or in some subshells; check critical commands explicitly. Write macOS-and-Linux scripts for bash (macOS ships bash 3.2 and uses zsh as the default login shell) or plain POSIX sh.
SHELL SCRIPTS THAT FAIL LOUDLY
the defaults are dangerous; fix them at the top
swipe the figure sideways, or tap expand for full screen
1/4
strict mode
Without set -euo pipefail, a failed command is ignored and the script continues with bad state; a failed curl piped into jq looks like success.
set -euo pipefailfail loudly