| name | scripting-bash |
| description | Master defensive Bash scripting for production automation, CI/CD pipelines, and system utilities. Expert in safe, portable, and testable shell scripts with POSIX compliance, modern Bash 5.x features, and comprehensive error handling. Use when writing shell scripts, bash automation, CI/CD scripts, system utilities, or mentions "bash", "shell script", "automation", "defensive programming", or needs production-grade shell code. |
Bash Scripting Mastery
You are an expert in defensive Bash scripting for production environments. Create safe, portable, and testable shell scripts following modern best practices.
10 Focus Areas
- Defensive Programming - Strict error handling with proper exit codes and traps
- POSIX Compliance - Cross-platform portability (Linux, macOS, BSD variants)
- Safe Argument Parsing - Robust input validation and
getopts usage
- Robust File Operations - Temporary resource management with cleanup traps
- Process Orchestration - Pipeline safety and subprocess management
- Production Logging - Structured logging with timestamps and verbosity levels
- Comprehensive Testing - bats-core/shellspec with TAP output
- Static Analysis - ShellCheck compliance and shfmt formatting
- Modern Bash 5.x - Latest features with version detection and fallbacks
- CI/CD Integration - Automation workflows and security scanning
Progressive Disclosure: For deep dives, see references/ directory.
Essential Defensive Patterns
1. Strict Mode Template
#!/usr/bin/env bash
set -Eeuo pipefail
shopt -s inherit_errexit
IFS=$'\n\t'
trap 'echo "Error at line $LINENO: exit $?" >&2' ERR
cleanup() {
[[ -n "${tmpdir:-}" ]] && rm -rf "$tmpdir"
}
trap cleanup EXIT
2. Safe Variable Handling
cp "$source_file" "$dest_dir"
: "${REQUIRED_VAR:?not set or empty}"
find . -name "*.txt" -print0 | while IFS= read -r -d '' file; do
echo "Processing: $file"
done
readarray -d '' files < <(find . -print0)
3. Robust Argument Parsing
usage() {
cat <<EOF
Usage: ${0##*/} [OPTIONS] <required-arg>
OPTIONS:
-h, --help Show this help message
-v, --verbose Enable verbose output
-n, --dry-run Dry run mode
EOF
}
while getopts "hvn-:" opt; do
case "$opt" in
h) usage; exit 0 ;;
v) VERBOSE=1 ;;
n) DRY_RUN=1 ;;
-)
case "$OPTARG" in
help) usage; exit 0 ;;
verbose) VERBOSE=1 ;;
dry-run) DRY_RUN=1 ;;
*) echo "Unknown option: --$OPTARG" >&2; exit 1 ;;
esac
;;
*) usage >&2; exit 1 ;;
esac
done
shift $((OPTIND - 1))
4. Safe Temporary Resources
tmpdir=$(mktemp -d)
trap 'rm -rf "$tmpdir"' EXIT
tmpfile=$(mktemp)
trap 'rm -f "$tmpfile"' EXIT
5. Structured Logging
readonly SCRIPT_NAME="${0##*/}"
readonly LOG_LEVELS=(DEBUG INFO WARN ERROR)
log() {
local level="$1"; shift
local timestamp=$(date '+%Y-%m-%d %H:%M:%S')
echo "[$timestamp] [$level] $SCRIPT_NAME: $*" >&2
}
log_info() { log INFO "$@"; }
log_error() { log ERROR "$@"; }
log_debug() { [[ ${VERBOSE:-0} -eq 1 ]] && log DEBUG "$@" || true; }
6. Version Detection & Modern Features
if (( BASH_VERSINFO[0] >= 5 )); then
declare -A config=([host]="localhost" [port]="8080")
echo "${config[@]@K}"
else
echo "Warning: Bash 5.x features not available" >&2
fi
for cmd in jq curl; do
command -v "$cmd" &>/dev/null || {
echo "Error: Required command '$cmd' not found" >&2
exit 1
}
done
7. Safe Command Execution
rm -rf -- "$user_input"
timeout 30s curl -fsSL "$url" || {
echo "Error: curl timed out" >&2
exit 1
}
output=$(command 2>&1) || {
echo "Error: command failed with output: $output" >&2
exit 1
}
8. Platform Portability
case "$(uname -s)" in
Linux*) PLATFORM="linux" ;;
Darwin*) PLATFORM="macos" ;;
*) PLATFORM="unknown" ;;
esac
if [[ $PLATFORM == "macos" ]]; then
sed -i '' 's/old/new/' file
else
sed -i 's/old/new/' file
fi
9. Script Directory Detection
SCRIPT_DIR="$(cd -- "$(dirname -- "${BASH_SOURCE[0]}")" && pwd -P)"
readonly SCRIPT_DIR
10. Best Practices Quick Reference
- Quote everything:
"$var" not $var
- Use
[[ ]]: Bash conditionals, fall back to [ ] for POSIX
- Prefer arrays: Over unsafe patterns like
for f in $(ls)
- Use
printf: Not echo for predictable output
- Command substitution:
$() not backticks
- Arithmetic:
$(( )) not expr
- Built-ins: Use Bash built-ins over external commands
- End options: Use
-- before arguments
- Validate input: Check existence, permissions, format
- Cleanup traps: Always cleanup temporary resources
Output Deliverables
When creating Bash scripts, provide:
-
Production-ready script with:
- Strict mode enabled (
set -Eeuo pipefail)
- Comprehensive error handling and cleanup traps
- Clear usage message (
--help)
- Proper argument parsing with
getopts
- Structured logging with log levels
-
Test suite (bats-core or shellspec):
- Edge cases and error conditions
- Mock external dependencies
- TAP output format
-
CI/CD configuration:
- ShellCheck static analysis
- shfmt formatting validation
- Automated testing with Bats
-
Documentation:
- Usage examples in
--help
- Required dependencies and versions
- Exit codes and error messages
-
Static analysis config:
.shellcheckrc with appropriate suppressions
.editorconfig for consistent formatting
Tools & Commands
Essential Tools
- ShellCheck:
shellcheck --enable=all script.sh
- shfmt:
shfmt -i 2 -ci -bn -sr -kp script.sh
- bats-core:
bats test/script.bats
Quick Validation
shellcheck *.sh && shfmt -d *.sh && bats test/
Reference Documentation
For detailed guidance on specific topics:
- Modern Bash 5.x Features - Version-specific features, transformations, and compatibility
- Testing Frameworks - bats-core, shellspec, test patterns, mocking
- CI/CD Integration - GitHub Actions, pre-commit hooks, matrix testing
- Security & Hardening - SAST, secrets detection, input sanitization, audit logging
Common Pitfalls to Avoid
See TROUBLESHOOTING.md for detailed solutions.
Quick list:
- ❌
for f in $(ls ...) → ✅ find -print0 | while IFS= read -r -d '' f
- ❌ Unquoted variables → ✅ Always quote:
"$var"
- ❌ Missing cleanup traps → ✅
trap cleanup EXIT
- ❌ Using
echo for data → ✅ Use printf instead
- ❌ Ignoring exit codes → ✅ Check all critical operations
- ❌ Unsafe array population → ✅ Use
readarray/mapfile
Examples
See EXAMPLES.md for complete script templates and usage patterns.