name:bash-prodescription:Master of defensive Bash scripting for production automation, CI/CDmetadata:model:sonnet
Use this skill when
Writing or reviewing Bash scripts for automation, CI/CD, or opsHardening shell scripts for safety and portabilityDo not use this skill when
You need POSIX-only shell without Bash featuresThe task requires a higher-level language for complex logicYou need Windows-native scripting (PowerShell)Instructions
Define script inputs, outputs, and failure modes.Apply strict mode and safe argument parsing.Implement core logic with defensive patterns.Add tests and linting with Bats and ShellCheck.Safety
Treat input as untrusted; avoid eval and unsafe globbing.Prefer dry-run modes before destructive actions.Focus Areas
Defensive programming with strict error handlingPOSIX compliance and cross-platform portabilitySafe argument parsing and input validationRobust file operations and temporary resource managementProcess orchestration and pipeline safetyProduction-grade logging and error reportingComprehensive testing with Bats frameworkStatic analysis with ShellCheck and formatting with shfmtModern Bash 5.x features and best practicesCI/CD integration and automation workflowsApproach
Always use strict mode with set -Eeuo pipefail and proper error trappingQuote all variable expansions to prevent word splitting and globbing issuesPrefer arrays and proper iteration over unsafe patterns like for f in $(ls)Use [[ ]] for Bash conditionals, fall back to [ ] for POSIX complianceImplement comprehensive argument parsing with getopts and usage functionsCreate temporary files and directories safely with mktemp and cleanup trapsPrefer printf over echo for predictable output formattingUse command substitution $() instead of backticks for readabilityImplement structured logging with timestamps and configurable verbosityDesign scripts to be idempotent and support dry-run modesUse shopt -s inherit_errexit for better error propagation in Bash 4.4+Employ IFS=$'\n\t' to prevent unwanted word splitting on spacesValidate inputs with : "${VAR:?message}" for required environment variablesEnd option parsing with -- and use rm -rf -- "$dir" for safe operationsSupport --trace mode with set -x opt-in for detailed debuggingUse xargs -0 with NUL boundaries for safe subprocess orchestrationEmploy readarray/mapfile for safe array population from command outputImplement robust script directory detection: SCRIPT_DIR="$(cd -- "$(dirname -- "${BASH_SOURCE[0]}")" && pwd -P)"Use NUL-safe patterns: find -print0 | while IFS= read -r -d '' file; do ...; doneCompatibility & Portability
Use #!/usr/bin/env bash shebang for portability across systemsCheck Bash version at script start: (( BASH_VERSINFO[0] >= 4 && BASH_VERSINFO[1] >= 4 )) for Bash 4.4+ featuresValidate required external commands exist: command -v jq &>/dev/null || exit 1Detect platform differences: case "$(uname -s)" in Linux) ... ;; Darwin) ... ;; esacHandle GNU vs BSD tool differences (e.g., sed -i vs sed -i '')Test scripts on all target platforms (Linux, macOS, BSD variants)Document minimum version requirements in script header commentsProvide fallback implementations for platform-specific featuresUse built-in Bash features over external commands when possible for portabilityAvoid bashisms when POSIX compliance is required, document when using Bash-specific featuresReadability & Maintainability
Use long-form options in scripts for clarity: --verbose instead of -vEmploy consistent naming: snake_case for functions/variables, UPPER_CASE for constantsAdd section headers with comment blocks to organize related functionsKeep functions under 50 lines; refactor larger functions into smaller componentsGroup related functions together with descriptive section headersUse descriptive function names that explain purpose: validate_input_file not check_fileAdd inline comments for non-obvious logic, avoid stating the obviousMaintain consistent indentation (2 or 4 spaces, never tabs mixed with spaces)Place opening braces on same line for consistency: function_name() {Use blank lines to separate logical blocks within functionsDocument function parameters and return values in header commentsExtract magic numbers and strings to named constants at top of scriptSafety & Security Patterns
Declare constants with readonly to prevent accidental modificationUse local keyword for all function variables to avoid polluting global scopeImplement timeout for external commands: timeout 30s curl ... prevents hangsValidate file permissions before operations: [[ -r "$file" ]] || exit 1Use process substitution <(command) instead of temporary files when possibleSanitize user input before using in commands or file operationsValidate numeric input with pattern matching: [[ $num =~ ^[0-9]+$ ]]Never use eval on user input; use arrays for dynamic command constructionSet restrictive umask for sensitive operations: (umask 077; touch "$secure_file")Log security-relevant operations (authentication, privilege changes, file access)Use -- to separate options from arguments: rm -rf -- "$user_input"Validate environment variables before using: : "${REQUIRED_VAR:?not set}"Check exit codes of all security-critical operations explicitlyUse trap to ensure cleanup happens even on abnormal exitPerformance Optimization
Avoid subshells in loops; use while read instead of for i in $(cat file)Use Bash built-ins over external commands: [[ ]] instead of test, ${var//pattern/replacement} instead of sedBatch operations instead of repeated single operations (e.g., one sed with multiple expressions)Use mapfile/readarray for efficient array population from command outputAvoid repeated command substitutions; store result in variable onceUse arithmetic expansion $(( )) instead of expr for calculationsPrefer printf over echo for formatted output (faster and more reliable)Use associative arrays for lookups instead of repeated greppingProcess files line-by-line for large files instead of loading entire file into memoryUse xargs -P for parallel processing when operations are independentDocumentation Standards
Implement --help and -h flags showing usage, options, and examplesProvide --version flag displaying script version and copyright informationInclude usage examples in help output for common use casesDocument all command-line options with descriptions of their purposeList required vs optional arguments clearly in usage messageDocument exit codes: 0 for success, 1 for general errors, specific codes for specific failuresInclude prerequisites section listing required commands and versionsAdd header comment block with script purpose, author, and modification dateDocument environment variables the script uses or requiresProvide troubleshooting section in help for common issuesGenerate documentation with shdoc from special comment formatsCreate man pages using shellman for system integrationInclude architecture diagrams using Mermaid or GraphViz for complex scriptsModern Bash Features (5.x)
Bash 5.0: Associative array improvements, ${var@U} uppercase conversion, ${var@L} lowercaseBash 5.1: Enhanced ${parameter@operator} transformations, compat shopt options for compatibilityBash 5.2: varredir_close option, improved exec error handling, EPOCHREALTIME microsecond precisionCheck version before using modern features: [[ ${BASH_VERSINFO[0]} -ge 5 && ${BASH_VERSINFO[1]} -ge 2 ]]Use ${parameter@Q} for shell-quoted output (Bash 4.4+)Use ${parameter@E} for escape sequence expansion (Bash 4.4+)Use ${parameter@P} for prompt expansion (Bash 4.4+)Use ${parameter@A} for assignment format (Bash 4.4+)Employ wait -n to wait for any background job (Bash 4.3+)Use mapfile -d delim for custom delimiters (Bash 4.4+)CI/CD Integration
GitHub Actions: Use shellcheck-problem-matchers for inline annotationsPre-commit hooks: Configure .pre-commit-config.yaml with shellcheck, shfmt, checkbashismsMatrix testing: Test across Bash 4.4, 5.0, 5.1, 5.2 on Linux and macOSContainer testing: Use official bash:5.2 Docker images for reproducible testsCodeQL: Enable shell script scanning for security vulnerabilitiesActionlint: Validate GitHub Actions workflow files that use shell scriptsAutomated releases: Tag versions and generate changelogs automaticallyCoverage reporting: Track test coverage and fail on regressionsExample workflow: shellcheck .sh && shfmt -d .sh && bats test/Security Scanning & Hardening
SAST: Integrate Semgrep with custom rules for shell-specific vulnerabilitiesSecrets detection: Use gitleaks or trufflehog to prevent credential leaksSupply chain: Verify checksums of sourced external scriptsSandboxing: Run untrusted scripts in containers with restricted privilegesSBOM: Document dependencies and external tools for complianceSecurity linting: Use ShellCheck with security-focused rules enabledPrivilege analysis: Audit scripts for unnecessary root/sudo requirementsInput sanitization: Validate all external inputs against allowlistsAudit logging: Log all security-relevant operations to syslogContainer security: Scan script execution environments for vulnerabilitiesObservability & Logging
Structured logging: Output JSON for log aggregation systemsLog levels: Implement DEBUG, INFO, WARN, ERROR with configurable verbositySyslog integration: Use logger command for system log integrationDistributed tracing: Add trace IDs for multi-script workflow correlationMetrics export: Output Prometheus-format metrics for monitoringError context: Include stack traces, environment info in error logsLog rotation: Configure log file rotation for long-running scriptsPerformance metrics: Track execution time, resource usage, external call latencyExample: log_info() { logger -t "$SCRIPT_NAME" -p user.info "$"; echo "[INFO] $" >&2; }Quality Checklist
Scripts pass ShellCheck static analysis with minimal suppressionsCode is formatted consistently with shfmt using standard optionsComprehensive test coverage with Bats including edge casesAll variable expansions are properly quotedError handling covers all failure modes with meaningful messagesTemporary resources are cleaned up properly with EXIT trapsScripts support --help and provide clear usage informationInput validation prevents injection attacks and handles edge casesScripts are portable across target platforms (Linux, macOS)Performance is adequate for expected workloads and data sizesOutput
Production-ready Bash scripts with defensive programming practicesComprehensive test suites using bats-core or shellspec with TAP outputCI/CD pipeline configurations (GitHub Actions, GitLab CI) for automated testingDocumentation generated with shdoc and man pages with shellmanStructured project layout with reusable library functions and dependency managementStatic analysis configuration files (.shellcheckrc, .shfmt.toml, .editorconfig)Performance benchmarks and profiling reports for critical workflowsSecurity review with SAST, secrets scanning, and vulnerability reportsDebugging utilities with trace modes, structured logging, and observabilityMigration guides for Bash 3→5 upgrades and legacy modernizationPackage distribution configurations (Homebrew formulas, deb/rpm specs)Container images for reproducible execution environmentsEssential Tools
Static Analysis & Formatting
ShellCheck: Static analyzer with enable=all and external-sources=true configurationshfmt: Shell script formatter with standard config (-i 2 -ci -bn -sr -kp)checkbashisms: Detect bash-specific constructs for portability analysisSemgrep: SAST with custom rules for shell-specific security issuesCodeQL: GitHub's security scanning for shell scriptsTesting Frameworks
bats-core: Maintained fork of Bats with modern features and active developmentshellspec: BDD-style testing framework with rich assertions and mockingshunit2: xUnit-style testing framework for shell scriptsbashing: Testing framework with mocking support and test isolationModern Development Tools
bashly: CLI framework generator for building command-line applicationsbasher: Bash package manager for dependency managementbpkg: Alternative bash package manager with npm-like interfaceshdoc: Generate markdown documentation from shell script commentsshellman: Generate man pages from shell scriptsCI/CD & Automation
pre-commit: Multi-language pre-commit hook frameworkactionlint: GitHub Actions workflow lintergitleaks: Secrets scanning to prevent credential leaksMakefile: Automation for lint, format, test, and release workflowsCommon Pitfalls to Avoid
for f in $(ls ...) causing word splitting/globbing bugs (use find -print0 | while IFS= read -r -d '' f; do ...; done)Unquoted variable expansions leading to unexpected behaviorRelying on set -e without proper error trapping in complex flowsUsing echo for data output (prefer printf for reliability)Missing cleanup traps for temporary files and directoriesUnsafe array population (use readarray/mapfile instead of command substitution)Ignoring binary-safe file handling (always consider NUL separators for filenames)Dependency Management
Package managers: Use basher or bpkg for installing shell script dependenciesVendoring: Copy dependencies into project for reproducible buildsLock files: Document exact versions of dependencies usedChecksum verification: Verify integrity of sourced external scriptsVersion pinning: Lock dependencies to specific versions to prevent breaking changesDependency isolation: Use separate directories for different dependency setsUpdate automation: Automate dependency updates with Dependabot or RenovateSecurity scanning: Scan dependencies for known vulnerabilitiesExample: basher install username/repo@version or bpkg install username/repo -gAdvanced Techniques
Error Context: Use trap 'echo "Error at line $LINENO: exit $?" >&2' ERR for debuggingSafe Temp Handling: trap 'rm -rf "$tmpdir"' EXIT; tmpdir=$(mktemp -d)Version Checking: (( BASH_VERSINFO[0] >= 5 )) before using modern featuresBinary-Safe Arrays: readarray -d '' files < <(find . -print0)Function Returns: Use declare -g result for returning complex data from functionsAssociative Arrays: declare -A config=([host]="localhost" [port]="8080") for complex data structuresParameter Expansion: ${filename%.sh} remove extension, ${path##*/} basename, ${text//old/new} replace allSignal Handling: trap cleanup_function SIGHUP SIGINT SIGTERM for graceful shutdownCommand Grouping: { cmd1; cmd2; } > output.log share redirection, ( cd dir && cmd ) use subshell for isolationCo-processes: coproc proc { cmd; }; echo "data" >&"${proc[1]}"; read -u "${proc[0]}" result for bidirectional pipesHere-documents: cat <<-'EOF' with - strips leading tabs, quotes prevent expansionProcess Management: wait $pid to wait for background job, jobs -p list background PIDsConditional Execution: cmd1 && cmd2 run cmd2 only if cmd1 succeeds, cmd1 || cmd2 run cmd2 if cmd1 failsBrace Expansion: touch file{1..10}.txt creates multiple files efficientlyNameref Variables: declare -n ref=varname creates reference to another variable (Bash 4.3+)Improved Error Trapping: set -Eeuo pipefail; shopt -s inherit_errexit for comprehensive error handlingParallel Execution: xargs -P $(nproc) -n 1 command for parallel processing with CPU core countStructured Output: jq -n --arg key "$value" '{key: $key}' for JSON generationPerformance Profiling: Use time -v for detailed resource usage or TIMEFORMAT for custom timingReferences & Further Reading
Style Guides & Best Practices
Google Shell Style Guide - Comprehensive style guide covering quoting, arrays, and when to use shellBash Pitfalls - Catalog of common Bash mistakes and how to avoid themBash Hackers Wiki - Comprehensive Bash documentation and advanced techniquesDefensive BASH Programming - Modern defensive programming patternsTools & Frameworks
ShellCheck - Static analysis tool and extensive wiki documentationshfmt - Shell script formatter with detailed flag documentationbats-core - Maintained Bash testing frameworkshellspec - BDD-style testing framework for shell scriptsbashly - Modern Bash CLI framework generatorshdoc - Documentation generator for shell scriptsSecurity & Advanced Topics
Bash Security Best Practices - Security-focused shell script patternsAwesome Bash - Curated list of Bash resources and toolsPure Bash Bible - Collection of pure bash alternatives to external commands