Deployment, Versioning, and Backward Compatibility
A Bash script used by CI or other automation becomes a software product with consumers. Flags, defaults, exit statuses, outputs, and paths must evolve intentionally.
Learning objectives
By the end of this lesson
- Version production Bash tools.
- Preserve stable flags and defaults.
- Deprecate before removing interfaces.
- Version structured output when needed.
- Stage and validate before promotion.
1. A mature Bash CLI has consumers
Once a shell tool is used by CI, cron, operators, or other scripts, its flags, defaults, exit statuses, output fields, paths, and environment variables become interfaces.
flowchart LR
V1["version 1"] --> C["consumers"]
V2["version 2"] --> C
C --> Q{"compatible?"}
Q -->|"yes"| U["safe upgrade"]
Q -->|"no"| M["migration required"]2. Give the tool a version
TOOL_VERSION=2.1.0
case ${1:-} in
--version)
printf '%s\n' "$TOOL_VERSION"
exit 0
;;
esac3. Defaults are compatibility too
Changing a default environment, timeout, output format, or destructive behavior can break callers even if every flag name remains unchanged.
4. Deprecate before removing
if [[ -n ${OLD_ENV_VAR:-} ]]; then
printf 'warning: OLD_ENV_VAR is deprecated; use NEW_ENV_VAR\n' >&2
NEW_ENV_VAR=${NEW_ENV_VAR:-$OLD_ENV_VAR}
fi5. Version structured output when it evolves
jq -n --arg release_id "$release_id" '{schema_version:1, release_id:$release_id}'6. Stage and validate before promotion
install -m 0755 release.sh /usr/local/lib/mytool/release.sh.new
bash -n /usr/local/lib/mytool/release.sh.new
mv /usr/local/lib/mytool/release.sh.new /usr/local/lib/mytool/release.shConsumers should never observe a partially written tool.
7. Test old calling conventions
Backward-compatibility tests should run representative older flags, environment variables, and output consumers against the new version.
8. Hands-on lab: versioned CLI with deprecated input
mkdir -p "$HOME/devops-academy/bash/chapter20/lesson03"
cd "$HOME/devops-academy/bash/chapter20/lesson03"
cat > tool.sh <<'EOF'
#!/usr/bin/env bash
set -u
TOOL_VERSION=2.0.0
case ${1:-} in
--version)
printf '%s\n' "$TOOL_VERSION"
exit 0
;;
esac
if [[ -n ${OLD_ENV:-} ]]; then
printf 'warning: OLD_ENV is deprecated; use NEW_ENV\n' >&2
NEW_ENV=${NEW_ENV:-$OLD_ENV}
fi
value=${NEW_ENV:-default}
printf '{"schema_version":1,"value":"%s"}\n' "$value"
EOF
chmod u+x tool.sh
./tool.sh --version
OLD_ENV=legacy ./tool.sh
NEW_ENV=current ./tool.shVerification checklist
9. Knowledge check
Question 1. What becomes a compatibility interface?
Question 2. Why deprecate first?
Question 3. Why version structured output?
Question 4. What should happen before promotion?
10. Summary
Treat production Bash tools as released software: version them, preserve stable contracts, deprecate before removal, test compatibility, and deploy staged known-good versions.
11. Further reading
- Semantic Versioning specification.
- Command Line Interface Guidelines.
- GNU Coreutils documentation — install and mv.
- Release-engineering guidance on deprecation and compatibility.
Keep the academy open
Support free, practical DevOps education.
Every lesson is designed to remain readable in a browser, downloadable from GitHub, and usable without a paid learning platform. Contributions help expand and maintain the curriculum.
0x716c4Ab160C4B66F31a28AE2448BfF68fc3a2ef0
Send only Ethereum/ERC-20 compatible assets to this address.