Developing Bash
Expert guidance for writing robust, portable shell scripts.
Quick Start
For immediate help, identify your task type and consult the relevant reference:
| Working On | Reference File | Key Topics |
|---|---|---|
| Portable scripts, sh compatibility | posix-scripting | POSIX subset, portability |
| Arrays, advanced expansion | bash-features | Bash-specific extensions |
| Error handling, safety flags | defensive-patterns | set flags, traps, validation |
| macOS vs Linux differences | cross-platform | GNU vs BSD, path differences |
Core Principles
These principles apply across all shell scripting:
Defensive by Default
- •Start every script with safety flags:
set -euo pipefail - •Quote all variable expansions:
"$var"not$var - •Use
[[ ]]for conditionals in Bash (more predictable than[ ]) - •Validate inputs before using them
- •Clean up resources with traps
Explicit Over Clever
- •Prefer readable pipelines over dense one-liners
- •Use descriptive variable names:
input_filenotf - •Add comments for non-obvious shell constructs
- •Avoid relying on shell-specific behavior without documenting it
Fail Fast, Fail Loud
- •Exit immediately on errors (
set -e) - •Treat unset variables as errors (
set -u) - •Propagate pipeline failures (
set -o pipefail) - •Provide meaningful error messages with context
Portability Awareness
- •Know your target: POSIX sh, Bash 3.x, Bash 4+, or Zsh
- •Document shell requirements in script header
- •Test on target platforms, not just development machine
- •Prefer POSIX when portability matters more than features
Script Template
bash
#!/usr/bin/env bash
set -euo pipefail
# Description: What this script does
# Usage: script.sh <arg1> [arg2]
readonly SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
readonly SCRIPT_NAME="$(basename "$0")"
cleanup() {
# Remove temp files, kill background processes
:
}
trap cleanup EXIT
die() {
echo "${SCRIPT_NAME}: error: $*" >&2
exit 1
}
usage() {
echo "Usage: ${SCRIPT_NAME} <arg1> [arg2]"
exit 1
}
main() {
[[ $# -lt 1 ]] && usage
local arg1="$1"
# Implementation here
}
main "$@"
Anti-Patterns to Avoid
Safety Violations
- •Unquoted variables:
$varinstead of"$var" - •Missing error handling: no
set -eor explicit checks - •Parsing
lsoutput instead of using globs orfind -print0 - •Using
evalwith untrusted input
Portability Traps
- •Bash arrays in
#!/bin/shscripts - •GNU-specific flags without fallbacks
- •Hardcoded paths (
/usr/local/binvs/usr/bin) - •Assuming
echobehavior (useprintffor portability)
Maintainability Issues
- •Magic numbers without explanation
- •Deep nesting instead of early returns
- •Massive functions doing multiple things
- •No usage message or help flag
Reference File IDs
For programmatic access: posix-scripting · bash-features · defensive-patterns · cross-platform