[{"data":1,"prerenderedAt":-1},["ShallowReactive",2],{"skill:01M70KDQ8692D51R6PBT5THXPD":3,"skill-same:01M70KDQ8692D51R6PBT5THXPD":73},{"skillNo":4,"name":5,"nameZh":6,"description":7,"descriptionZh":6,"repositoryFullName":8,"ownerLogin":9,"ownerAvatarUrl":10,"ownerAccountNo":11,"ownerDisplayName":12,"repositoryNo":13,"starsCount":14,"licenseSpdxId":15,"licenseFileUrl":6,"sourceHtmlUrl":16,"categories":17,"keywords":23,"publishedAt":44,"linkOnly":45,"markdownContent":46,"markdownBody":47,"frontMatter":48,"refName":49,"commitSha":50,"skillDirectory":51,"forksCount":52,"repositoryHtmlUrl":53,"repositoryHomepageUrl":54,"ownerHtmlUrl":55,"ownerBlogUrl":56,"ownerDescription":57,"updatedAt":58,"install":59,"resources":72},"01M70KDQ8692D51R6PBT5THXPD","bash-defensive-patterns",null,"Master defensive Bash programming techniques for production-grade scripts. Use when writing robust shell scripts, CI\u002FCD pipelines, or system utilities requiring fault tolerance and safety.","shengdabai\u002FTony-Claude-Code-Skills","shengdabai","https:\u002F\u002Favatars.githubusercontent.com\u002Fu\u002F116417419?v=4","01M70F6D2WY5PQV5A92BKYJQEW","Tony Sheng","01M70F6D3GAAAYZ5H4CC1G8VXM",3,"MIT","https:\u002F\u002Fgithub.com\u002Fshengdabai\u002FTony-Claude-Code-Skills\u002Fblob\u002Fmain\u002Fskills\u002F_collections\u002Fwshobson-agents\u002Fplugins\u002Fshell-scripting\u002Fskills\u002Fbash-defensive-patterns\u002FSKILL.md",[18],{"categoryNo":19,"categoryName":20,"taxonomyType":21,"taxonomyTypeDesc":22},"01JBSEEDCAT000000000000030","开发工程师","PROFESSION","适用职业",[24,25,26,27,28,29,30,31,32,33,34,35,36,37,38,39,40,41,42,43],"Bash","defensive","bash defensive patterns","patterns","when","writing","for","techniques","tolerance","Utilities","CI\u002FCD","scripts","fault tolerance","master","use","programming","system","shell scripts","Safety","ci","2026-11-10 10:12:30",false,"---\nname: bash-defensive-patterns\ndescription: Master defensive Bash programming techniques for production-grade scripts. Use when writing robust shell scripts, CI\u002FCD pipelines, or system utilities requiring fault tolerance and safety.\n---\n\n# Bash Defensive Patterns\n\nComprehensive guidance for writing production-ready Bash scripts using defensive programming techniques, error handling, and safety best practices to prevent common pitfalls and ensure reliability.\n\n## When to Use This Skill\n\n- Writing production automation scripts\n- Building CI\u002FCD pipeline scripts\n- Creating system administration utilities\n- Developing error-resilient deployment automation\n- Writing scripts that must handle edge cases safely\n- Building maintainable shell script libraries\n- Implementing comprehensive logging and monitoring\n- Creating scripts that must work across different platforms\n\n## Core Defensive Principles\n\n### 1. Strict Mode\nEnable bash strict mode at the start of every script to catch errors early.\n\n```bash\n#!\u002Fbin\u002Fbash\nset -Eeuo pipefail  # Exit on error, unset variables, pipe failures\n```\n\n**Key flags:**\n- `set -E`: Inherit ERR trap in functions\n- `set -e`: Exit on any error (command returns non-zero)\n- `set -u`: Exit on undefined variable reference\n- `set -o pipefail`: Pipe fails if any command fails (not just last)\n\n### 2. Error Trapping and Cleanup\nImplement proper cleanup on script exit or error.\n\n```bash\n#!\u002Fbin\u002Fbash\nset -Eeuo pipefail\n\ntrap 'echo \"Error on line $LINENO\"' ERR\ntrap 'echo \"Cleaning up...\"; rm -rf \"$TMPDIR\"' EXIT\n\nTMPDIR=$(mktemp -d)\n# Script code here\n```\n\n### 3. Variable Safety\nAlways quote variables to prevent word splitting and globbing issues.\n\n```bash\n# Wrong - unsafe\ncp $source $dest\n\n# Correct - safe\ncp \"$source\" \"$dest\"\n\n# Required variables - fail with message if unset\n: \"${REQUIRED_VAR:?REQUIRED_VAR is not set}\"\n```\n\n### 4. Array Handling\nUse arrays safely for complex data handling.\n\n```bash\n# Safe array iteration\ndeclare -a items=(\"item 1\" \"item 2\" \"item 3\")\n\nfor item in \"${items[@]}\"; do\n    echo \"Processing: $item\"\ndone\n\n# Reading output into array safely\nmapfile -t lines \u003C \u003C(some_command)\nreadarray -t numbers \u003C \u003C(seq 1 10)\n```\n\n### 5. Conditional Safety\nUse `[[ ]]` for Bash-specific features, `[ ]` for POSIX.\n\n```bash\n# Bash - safer\nif [[ -f \"$file\" && -r \"$file\" ]]; then\n    content=$(\u003C\"$file\")\nfi\n\n# POSIX - portable\nif [ -f \"$file\" ] && [ -r \"$file\" ]; then\n    content=$(cat \"$file\")\nfi\n\n# Test for existence before operations\nif [[ -z \"${VAR:-}\" ]]; then\n    echo \"VAR is not set or is empty\"\nfi\n```\n\n## Fundamental Patterns\n\n### Pattern 1: Safe Script Directory Detection\n\n```bash\n#!\u002Fbin\u002Fbash\nset -Eeuo pipefail\n\n# Correctly determine script directory\nSCRIPT_DIR=\"$(cd -- \"$(dirname -- \"${BASH_SOURCE[0]}\")\" && pwd -P)\"\nSCRIPT_NAME=\"$(basename -- \"${BASH_SOURCE[0]}\")\"\n\necho \"Script location: $SCRIPT_DIR\u002F$SCRIPT_NAME\"\n```\n\n### Pattern 2: Comprehensive Function Templat\n\n```bash\n#!\u002Fbin\u002Fbash\nset -Eeuo pipefail\n\n# Prefix for functions: handle_*, process_*, check_*, validate_*\n# Include documentation and error handling\n\nvalidate_file() {\n    local -r file=\"$1\"\n    local -r message=\"${2:-File not found: $file}\"\n\n    if [[ ! -f \"$file\" ]]; then\n        echo \"ERROR: $message\" >&2\n        return 1\n    fi\n    return 0\n}\n\nprocess_files() {\n    local -r input_dir=\"$1\"\n    local -r output_dir=\"$2\"\n\n    # Validate inputs\n    [[ -d \"$input_dir\" ]] || { echo \"ERROR: input_dir not a directory\" >&2; return 1; }\n\n    # Create output directory if needed\n    mkdir -p \"$output_dir\" || { echo \"ERROR: Cannot create output_dir\" >&2; return 1; }\n\n    # Process files safely\n    while IFS= read -r -d '' file; do\n        echo \"Processing: $file\"\n        # Do work\n    done \u003C \u003C(find \"$input_dir\" -maxdepth 1 -type f -print0)\n\n    return 0\n}\n```\n\n### Pattern 3: Safe Temporary File Handling\n\n```bash\n#!\u002Fbin\u002Fbash\nset -Eeuo pipefail\n\ntrap 'rm -rf -- \"$TMPDIR\"' EXIT\n\n# Create temporary directory\nTMPDIR=$(mktemp -d) || { echo \"ERROR: Failed to create temp directory\" >&2; exit 1; }\n\n# Create temporary files in directory\nTMPFILE1=\"$TMPDIR\u002Ftemp1.txt\"\nTMPFILE2=\"$TMPDIR\u002Ftemp2.txt\"\n\n# Use temporary files\ntouch \"$TMPFILE1\" \"$TMPFILE2\"\n\necho \"Temp files created in: $TMPDIR\"\n```\n\n### Pattern 4: Robust Argument Parsing\n\n```bash\n#!\u002Fbin\u002Fbash\nset -Eeuo pipefail\n\n# Default values\nVERBOSE=false\nDRY_RUN=false\nOUTPUT_FILE=\"\"\nTHREADS=4\n\nusage() {\n    cat \u003C\u003CEOF\nUsage: $0 [OPTIONS]\n\nOptions:\n    -v, --verbose       Enable verbose output\n    -d, --dry-run       Run without making changes\n    -o, --output FILE   Output file path\n    -j, --jobs NUM      Number of parallel jobs\n    -h, --help          Show this help message\nEOF\n    exit \"${1:-0}\"\n}\n\n# Parse arguments\nwhile [[ $# -gt 0 ]]; do\n    case \"$1\" in\n        -v|--verbose)\n            VERBOSE=true\n            shift\n            ;;\n        -d|--dry-run)\n            DRY_RUN=true\n            shift\n            ;;\n        -o|--output)\n            OUTPUT_FILE=\"$2\"\n            shift 2\n            ;;\n        -j|--jobs)\n            THREADS=\"$2\"\n            shift 2\n            ;;\n        -h|--help)\n            usage 0\n            ;;\n        --)\n            shift\n            break\n            ;;\n        *)\n            echo \"ERROR: Unknown option: $1\" >&2\n            usage 1\n            ;;\n    esac\ndone\n\n# Validate required arguments\n[[ -n \"$OUTPUT_FILE\" ]] || { echo \"ERROR: -o\u002F--output is required\" >&2; usage 1; }\n```\n\n### Pattern 5: Structured Logging\n\n```bash\n#!\u002Fbin\u002Fbash\nset -Eeuo pipefail\n\n# Logging functions\nlog_info() {\n    echo \"[$(date +'%Y-%m-%d %H:%M:%S')] INFO: $*\" >&2\n}\n\nlog_warn() {\n    echo \"[$(date +'%Y-%m-%d %H:%M:%S')] WARN: $*\" >&2\n}\n\nlog_error() {\n    echo \"[$(date +'%Y-%m-%d %H:%M:%S')] ERROR: $*\" >&2\n}\n\nlog_debug() {\n    if [[ \"${DEBUG:-0}\" == \"1\" ]]; then\n        echo \"[$(date +'%Y-%m-%d %H:%M:%S')] DEBUG: $*\" >&2\n    fi\n}\n\n# Usage\nlog_info \"Starting script\"\nlog_debug \"Debug information\"\nlog_warn \"Warning message\"\nlog_error \"Error occurred\"\n```\n\n### Pattern 6: Process Orchestration with Signals\n\n```bash\n#!\u002Fbin\u002Fbash\nset -Eeuo pipefail\n\n# Track background processes\nPIDS=()\n\ncleanup() {\n    log_info \"Shutting down...\"\n\n    # Terminate all background processes\n    for pid in \"${PIDS[@]}\"; do\n        if kill -0 \"$pid\" 2>\u002Fdev\u002Fnull; then\n            kill -TERM \"$pid\" 2>\u002Fdev\u002Fnull || true\n        fi\n    done\n\n    # Wait for graceful shutdown\n    for pid in \"${PIDS[@]}\"; do\n        wait \"$pid\" 2>\u002Fdev\u002Fnull || true\n    done\n}\n\ntrap cleanup SIGTERM SIGINT\n\n# Start background tasks\nbackground_task &\nPIDS+=($!)\n\nanother_task &\nPIDS+=($!)\n\n# Wait for all background processes\nwait\n```\n\n### Pattern 7: Safe File Operations\n\n```bash\n#!\u002Fbin\u002Fbash\nset -Eeuo pipefail\n\n# Use -i flag to move safely without overwriting\nsafe_move() {\n    local -r source=\"$1\"\n    local -r dest=\"$2\"\n\n    if [[ ! -e \"$source\" ]]; then\n        echo \"ERROR: Source does not exist: $source\" >&2\n        return 1\n    fi\n\n    if [[ -e \"$dest\" ]]; then\n        echo \"ERROR: Destination already exists: $dest\" >&2\n        return 1\n    fi\n\n    mv \"$source\" \"$dest\"\n}\n\n# Safe directory cleanup\nsafe_rmdir() {\n    local -r dir=\"$1\"\n\n    if [[ ! -d \"$dir\" ]]; then\n        echo \"ERROR: Not a directory: $dir\" >&2\n        return 1\n    fi\n\n    # Use -I flag to prompt before rm (BSD\u002FGNU compatible)\n    rm -rI -- \"$dir\"\n}\n\n# Atomic file writes\natomic_write() {\n    local -r target=\"$1\"\n    local -r tmpfile\n    tmpfile=$(mktemp) || return 1\n\n    # Write to temp file first\n    cat > \"$tmpfile\"\n\n    # Atomic rename\n    mv \"$tmpfile\" \"$target\"\n}\n```\n\n### Pattern 8: Idempotent Script Design\n\n```bash\n#!\u002Fbin\u002Fbash\nset -Eeuo pipefail\n\n# Check if resource already exists\nensure_directory() {\n    local -r dir=\"$1\"\n\n    if [[ -d \"$dir\" ]]; then\n        log_info \"Directory already exists: $dir\"\n        return 0\n    fi\n\n    mkdir -p \"$dir\" || {\n        log_error \"Failed to create directory: $dir\"\n        return 1\n    }\n\n    log_info \"Created directory: $dir\"\n}\n\n# Ensure configuration state\nensure_config() {\n    local -r config_file=\"$1\"\n    local -r default_value=\"$2\"\n\n    if [[ ! -f \"$config_file\" ]]; then\n        echo \"$default_value\" > \"$config_file\"\n        log_info \"Created config: $config_file\"\n    fi\n}\n\n# Rerunning script multiple times should be safe\nensure_directory \"\u002Fvar\u002Fcache\u002Fmyapp\"\nensure_config \"\u002Fetc\u002Fmyapp\u002Fconfig\" \"DEBUG=false\"\n```\n\n### Pattern 9: Safe Command Substitution\n\n```bash\n#!\u002Fbin\u002Fbash\nset -Eeuo pipefail\n\n# Use $() instead of backticks\nname=$(\u003C\"$file\")  # Modern, safe variable assignment from file\noutput=$(command -v python3)  # Get command location safely\n\n# Handle command substitution with error checking\nresult=$(command -v node) || {\n    log_error \"node command not found\"\n    return 1\n}\n\n# For multiple lines\nmapfile -t lines \u003C \u003C(grep \"pattern\" \"$file\")\n\n# NUL-safe iteration\nwhile IFS= read -r -d '' file; do\n    echo \"Processing: $file\"\ndone \u003C \u003C(find \u002Fpath -type f -print0)\n```\n\n### Pattern 10: Dry-Run Support\n\n```bash\n#!\u002Fbin\u002Fbash\nset -Eeuo pipefail\n\nDRY_RUN=\"${DRY_RUN:-false}\"\n\nrun_cmd() {\n    if [[ \"$DRY_RUN\" == \"true\" ]]; then\n        echo \"[DRY RUN] Would execute: $*\"\n        return 0\n    fi\n\n    \"$@\"\n}\n\n# Usage\nrun_cmd cp \"$source\" \"$dest\"\nrun_cmd rm \"$file\"\nrun_cmd chown \"$owner\" \"$target\"\n```\n\n## Advanced Defensive Techniques\n\n### Named Parameters Pattern\n\n```bash\n#!\u002Fbin\u002Fbash\nset -Eeuo pipefail\n\nprocess_data() {\n    local input_file=\"\"\n    local output_dir=\"\"\n    local format=\"json\"\n\n    # Parse named parameters\n    while [[ $# -gt 0 ]]; do\n        case \"$1\" in\n            --input=*)\n                input_file=\"${1#*=}\"\n                ;;\n            --output=*)\n                output_dir=\"${1#*=}\"\n                ;;\n            --format=*)\n                format=\"${1#*=}\"\n                ;;\n            *)\n                echo \"ERROR: Unknown parameter: $1\" >&2\n                return 1\n                ;;\n        esac\n        shift\n    done\n\n    # Validate required parameters\n    [[ -n \"$input_file\" ]] || { echo \"ERROR: --input is required\" >&2; return 1; }\n    [[ -n \"$output_dir\" ]] || { echo \"ERROR: --output is required\" >&2; return 1; }\n}\n```\n\n### Dependency Checking\n\n```bash\n#!\u002Fbin\u002Fbash\nset -Eeuo pipefail\n\ncheck_dependencies() {\n    local -a missing_deps=()\n    local -a required=(\"jq\" \"curl\" \"git\")\n\n    for cmd in \"${required[@]}\"; do\n        if ! command -v \"$cmd\" &>\u002Fdev\u002Fnull; then\n            missing_deps+=(\"$cmd\")\n        fi\n    done\n\n    if [[ ${#missing_deps[@]} -gt 0 ]]; then\n        echo \"ERROR: Missing required commands: ${missing_deps[*]}\" >&2\n        return 1\n    fi\n}\n\ncheck_dependencies\n```\n\n## Best Practices Summary\n\n1. **Always use strict mode** - `set -Eeuo pipefail`\n2. **Quote all variables** - `\"$variable\"` prevents word splitting\n3. **Use [[ ]] conditionals** - More robust than [ ]\n4. **Implement error trapping** - Catch and handle errors gracefully\n5. **Validate all inputs** - Check file existence, permissions, formats\n6. **Use functions for reusability** - Prefix with meaningful names\n7. **Implement structured logging** - Include timestamps and levels\n8. **Support dry-run mode** - Allow users to preview changes\n9. **Handle temporary files safely** - Use mktemp, cleanup with trap\n10. **Design for idempotency** - Scripts should be safe to rerun\n11. **Document requirements** - List dependencies and minimum versions\n12. **Test error paths** - Ensure error handling works correctly\n13. **Use `command -v`** - Safer than `which` for checking executables\n14. **Prefer printf over echo** - More predictable across systems\n\n## Resources\n\n- **Bash Strict Mode**: http:\u002F\u002Fredsymbol.net\u002Farticles\u002Funofficial-bash-strict-mode\u002F\n- **Google Shell Style Guide**: https:\u002F\u002Fgoogle.github.io\u002Fstyleguide\u002Fshellguide.html\n- **Defensive BASH Programming**: https:\u002F\u002Fwww.lifepipe.net\u002F\n","# Bash Defensive Patterns\n\nComprehensive guidance for writing production-ready Bash scripts using defensive programming techniques, error handling, and safety best practices to prevent common pitfalls and ensure reliability.\n\n## When to Use This Skill\n\n- Writing production automation scripts\n- Building CI\u002FCD pipeline scripts\n- Creating system administration utilities\n- Developing error-resilient deployment automation\n- Writing scripts that must handle edge cases safely\n- Building maintainable shell script libraries\n- Implementing comprehensive logging and monitoring\n- Creating scripts that must work across different platforms\n\n## Core Defensive Principles\n\n### 1. Strict Mode\nEnable bash strict mode at the start of every script to catch errors early.\n\n```bash\n#!\u002Fbin\u002Fbash\nset -Eeuo pipefail  # Exit on error, unset variables, pipe failures\n```\n\n**Key flags:**\n- `set -E`: Inherit ERR trap in functions\n- `set -e`: Exit on any error (command returns non-zero)\n- `set -u`: Exit on undefined variable reference\n- `set -o pipefail`: Pipe fails if any command fails (not just last)\n\n### 2. Error Trapping and Cleanup\nImplement proper cleanup on script exit or error.\n\n```bash\n#!\u002Fbin\u002Fbash\nset -Eeuo pipefail\n\ntrap 'echo \"Error on line $LINENO\"' ERR\ntrap 'echo \"Cleaning up...\"; rm -rf \"$TMPDIR\"' EXIT\n\nTMPDIR=$(mktemp -d)\n# Script code here\n```\n\n### 3. Variable Safety\nAlways quote variables to prevent word splitting and globbing issues.\n\n```bash\n# Wrong - unsafe\ncp $source $dest\n\n# Correct - safe\ncp \"$source\" \"$dest\"\n\n# Required variables - fail with message if unset\n: \"${REQUIRED_VAR:?REQUIRED_VAR is not set}\"\n```\n\n### 4. Array Handling\nUse arrays safely for complex data handling.\n\n```bash\n# Safe array iteration\ndeclare -a items=(\"item 1\" \"item 2\" \"item 3\")\n\nfor item in \"${items[@]}\"; do\n    echo \"Processing: $item\"\ndone\n\n# Reading output into array safely\nmapfile -t lines \u003C \u003C(some_command)\nreadarray -t numbers \u003C \u003C(seq 1 10)\n```\n\n### 5. Conditional Safety\nUse `[[ ]]` for Bash-specific features, `[ ]` for POSIX.\n\n```bash\n# Bash - safer\nif [[ -f \"$file\" && -r \"$file\" ]]; then\n    content=$(\u003C\"$file\")\nfi\n\n# POSIX - portable\nif [ -f \"$file\" ] && [ -r \"$file\" ]; then\n    content=$(cat \"$file\")\nfi\n\n# Test for existence before operations\nif [[ -z \"${VAR:-}\" ]]; then\n    echo \"VAR is not set or is empty\"\nfi\n```\n\n## Fundamental Patterns\n\n### Pattern 1: Safe Script Directory Detection\n\n```bash\n#!\u002Fbin\u002Fbash\nset -Eeuo pipefail\n\n# Correctly determine script directory\nSCRIPT_DIR=\"$(cd -- \"$(dirname -- \"${BASH_SOURCE[0]}\")\" && pwd -P)\"\nSCRIPT_NAME=\"$(basename -- \"${BASH_SOURCE[0]}\")\"\n\necho \"Script location: $SCRIPT_DIR\u002F$SCRIPT_NAME\"\n```\n\n### Pattern 2: Comprehensive Function Templat\n\n```bash\n#!\u002Fbin\u002Fbash\nset -Eeuo pipefail\n\n# Prefix for functions: handle_*, process_*, check_*, validate_*\n# Include documentation and error handling\n\nvalidate_file() {\n    local -r file=\"$1\"\n    local -r message=\"${2:-File not found: $file}\"\n\n    if [[ ! -f \"$file\" ]]; then\n        echo \"ERROR: $message\" >&2\n        return 1\n    fi\n    return 0\n}\n\nprocess_files() {\n    local -r input_dir=\"$1\"\n    local -r output_dir=\"$2\"\n\n    # Validate inputs\n    [[ -d \"$input_dir\" ]] || { echo \"ERROR: input_dir not a directory\" >&2; return 1; }\n\n    # Create output directory if needed\n    mkdir -p \"$output_dir\" || { echo \"ERROR: Cannot create output_dir\" >&2; return 1; }\n\n    # Process files safely\n    while IFS= read -r -d '' file; do\n        echo \"Processing: $file\"\n        # Do work\n    done \u003C \u003C(find \"$input_dir\" -maxdepth 1 -type f -print0)\n\n    return 0\n}\n```\n\n### Pattern 3: Safe Temporary File Handling\n\n```bash\n#!\u002Fbin\u002Fbash\nset -Eeuo pipefail\n\ntrap 'rm -rf -- \"$TMPDIR\"' EXIT\n\n# Create temporary directory\nTMPDIR=$(mktemp -d) || { echo \"ERROR: Failed to create temp directory\" >&2; exit 1; }\n\n# Create temporary files in directory\nTMPFILE1=\"$TMPDIR\u002Ftemp1.txt\"\nTMPFILE2=\"$TMPDIR\u002Ftemp2.txt\"\n\n# Use temporary files\ntouch \"$TMPFILE1\" \"$TMPFILE2\"\n\necho \"Temp files created in: $TMPDIR\"\n```\n\n### Pattern 4: Robust Argument Parsing\n\n```bash\n#!\u002Fbin\u002Fbash\nset -Eeuo pipefail\n\n# Default values\nVERBOSE=false\nDRY_RUN=false\nOUTPUT_FILE=\"\"\nTHREADS=4\n\nusage() {\n    cat \u003C\u003CEOF\nUsage: $0 [OPTIONS]\n\nOptions:\n    -v, --verbose       Enable verbose output\n    -d, --dry-run       Run without making changes\n    -o, --output FILE   Output file path\n    -j, --jobs NUM      Number of parallel jobs\n    -h, --help          Show this help message\nEOF\n    exit \"${1:-0}\"\n}\n\n# Parse arguments\nwhile [[ $# -gt 0 ]]; do\n    case \"$1\" in\n        -v|--verbose)\n            VERBOSE=true\n            shift\n            ;;\n        -d|--dry-run)\n            DRY_RUN=true\n            shift\n            ;;\n        -o|--output)\n            OUTPUT_FILE=\"$2\"\n            shift 2\n            ;;\n        -j|--jobs)\n            THREADS=\"$2\"\n            shift 2\n            ;;\n        -h|--help)\n            usage 0\n            ;;\n        --)\n            shift\n            break\n            ;;\n        *)\n            echo \"ERROR: Unknown option: $1\" >&2\n            usage 1\n            ;;\n    esac\ndone\n\n# Validate required arguments\n[[ -n \"$OUTPUT_FILE\" ]] || { echo \"ERROR: -o\u002F--output is required\" >&2; usage 1; }\n```\n\n### Pattern 5: Structured Logging\n\n```bash\n#!\u002Fbin\u002Fbash\nset -Eeuo pipefail\n\n# Logging functions\nlog_info() {\n    echo \"[$(date +'%Y-%m-%d %H:%M:%S')] INFO: $*\" >&2\n}\n\nlog_warn() {\n    echo \"[$(date +'%Y-%m-%d %H:%M:%S')] WARN: $*\" >&2\n}\n\nlog_error() {\n    echo \"[$(date +'%Y-%m-%d %H:%M:%S')] ERROR: $*\" >&2\n}\n\nlog_debug() {\n    if [[ \"${DEBUG:-0}\" == \"1\" ]]; then\n        echo \"[$(date +'%Y-%m-%d %H:%M:%S')] DEBUG: $*\" >&2\n    fi\n}\n\n# Usage\nlog_info \"Starting script\"\nlog_debug \"Debug information\"\nlog_warn \"Warning message\"\nlog_error \"Error occurred\"\n```\n\n### Pattern 6: Process Orchestration with Signals\n\n```bash\n#!\u002Fbin\u002Fbash\nset -Eeuo pipefail\n\n# Track background processes\nPIDS=()\n\ncleanup() {\n    log_info \"Shutting down...\"\n\n    # Terminate all background processes\n    for pid in \"${PIDS[@]}\"; do\n        if kill -0 \"$pid\" 2>\u002Fdev\u002Fnull; then\n            kill -TERM \"$pid\" 2>\u002Fdev\u002Fnull || true\n        fi\n    done\n\n    # Wait for graceful shutdown\n    for pid in \"${PIDS[@]}\"; do\n        wait \"$pid\" 2>\u002Fdev\u002Fnull || true\n    done\n}\n\ntrap cleanup SIGTERM SIGINT\n\n# Start background tasks\nbackground_task &\nPIDS+=($!)\n\nanother_task &\nPIDS+=($!)\n\n# Wait for all background processes\nwait\n```\n\n### Pattern 7: Safe File Operations\n\n```bash\n#!\u002Fbin\u002Fbash\nset -Eeuo pipefail\n\n# Use -i flag to move safely without overwriting\nsafe_move() {\n    local -r source=\"$1\"\n    local -r dest=\"$2\"\n\n    if [[ ! -e \"$source\" ]]; then\n        echo \"ERROR: Source does not exist: $source\" >&2\n        return 1\n    fi\n\n    if [[ -e \"$dest\" ]]; then\n        echo \"ERROR: Destination already exists: $dest\" >&2\n        return 1\n    fi\n\n    mv \"$source\" \"$dest\"\n}\n\n# Safe directory cleanup\nsafe_rmdir() {\n    local -r dir=\"$1\"\n\n    if [[ ! -d \"$dir\" ]]; then\n        echo \"ERROR: Not a directory: $dir\" >&2\n        return 1\n    fi\n\n    # Use -I flag to prompt before rm (BSD\u002FGNU compatible)\n    rm -rI -- \"$dir\"\n}\n\n# Atomic file writes\natomic_write() {\n    local -r target=\"$1\"\n    local -r tmpfile\n    tmpfile=$(mktemp) || return 1\n\n    # Write to temp file first\n    cat > \"$tmpfile\"\n\n    # Atomic rename\n    mv \"$tmpfile\" \"$target\"\n}\n```\n\n### Pattern 8: Idempotent Script Design\n\n```bash\n#!\u002Fbin\u002Fbash\nset -Eeuo pipefail\n\n# Check if resource already exists\nensure_directory() {\n    local -r dir=\"$1\"\n\n    if [[ -d \"$dir\" ]]; then\n        log_info \"Directory already exists: $dir\"\n        return 0\n    fi\n\n    mkdir -p \"$dir\" || {\n        log_error \"Failed to create directory: $dir\"\n        return 1\n    }\n\n    log_info \"Created directory: $dir\"\n}\n\n# Ensure configuration state\nensure_config() {\n    local -r config_file=\"$1\"\n    local -r default_value=\"$2\"\n\n    if [[ ! -f \"$config_file\" ]]; then\n        echo \"$default_value\" > \"$config_file\"\n        log_info \"Created config: $config_file\"\n    fi\n}\n\n# Rerunning script multiple times should be safe\nensure_directory \"\u002Fvar\u002Fcache\u002Fmyapp\"\nensure_config \"\u002Fetc\u002Fmyapp\u002Fconfig\" \"DEBUG=false\"\n```\n\n### Pattern 9: Safe Command Substitution\n\n```bash\n#!\u002Fbin\u002Fbash\nset -Eeuo pipefail\n\n# Use $() instead of backticks\nname=$(\u003C\"$file\")  # Modern, safe variable assignment from file\noutput=$(command -v python3)  # Get command location safely\n\n# Handle command substitution with error checking\nresult=$(command -v node) || {\n    log_error \"node command not found\"\n    return 1\n}\n\n# For multiple lines\nmapfile -t lines \u003C \u003C(grep \"pattern\" \"$file\")\n\n# NUL-safe iteration\nwhile IFS= read -r -d '' file; do\n    echo \"Processing: $file\"\ndone \u003C \u003C(find \u002Fpath -type f -print0)\n```\n\n### Pattern 10: Dry-Run Support\n\n```bash\n#!\u002Fbin\u002Fbash\nset -Eeuo pipefail\n\nDRY_RUN=\"${DRY_RUN:-false}\"\n\nrun_cmd() {\n    if [[ \"$DRY_RUN\" == \"true\" ]]; then\n        echo \"[DRY RUN] Would execute: $*\"\n        return 0\n    fi\n\n    \"$@\"\n}\n\n# Usage\nrun_cmd cp \"$source\" \"$dest\"\nrun_cmd rm \"$file\"\nrun_cmd chown \"$owner\" \"$target\"\n```\n\n## Advanced Defensive Techniques\n\n### Named Parameters Pattern\n\n```bash\n#!\u002Fbin\u002Fbash\nset -Eeuo pipefail\n\nprocess_data() {\n    local input_file=\"\"\n    local output_dir=\"\"\n    local format=\"json\"\n\n    # Parse named parameters\n    while [[ $# -gt 0 ]]; do\n        case \"$1\" in\n            --input=*)\n                input_file=\"${1#*=}\"\n                ;;\n            --output=*)\n                output_dir=\"${1#*=}\"\n                ;;\n            --format=*)\n                format=\"${1#*=}\"\n                ;;\n            *)\n                echo \"ERROR: Unknown parameter: $1\" >&2\n                return 1\n                ;;\n        esac\n        shift\n    done\n\n    # Validate required parameters\n    [[ -n \"$input_file\" ]] || { echo \"ERROR: --input is required\" >&2; return 1; }\n    [[ -n \"$output_dir\" ]] || { echo \"ERROR: --output is required\" >&2; return 1; }\n}\n```\n\n### Dependency Checking\n\n```bash\n#!\u002Fbin\u002Fbash\nset -Eeuo pipefail\n\ncheck_dependencies() {\n    local -a missing_deps=()\n    local -a required=(\"jq\" \"curl\" \"git\")\n\n    for cmd in \"${required[@]}\"; do\n        if ! command -v \"$cmd\" &>\u002Fdev\u002Fnull; then\n            missing_deps+=(\"$cmd\")\n        fi\n    done\n\n    if [[ ${#missing_deps[@]} -gt 0 ]]; then\n        echo \"ERROR: Missing required commands: ${missing_deps[*]}\" >&2\n        return 1\n    fi\n}\n\ncheck_dependencies\n```\n\n## Best Practices Summary\n\n1. **Always use strict mode** - `set -Eeuo pipefail`\n2. **Quote all variables** - `\"$variable\"` prevents word splitting\n3. **Use [[ ]] conditionals** - More robust than [ ]\n4. **Implement error trapping** - Catch and handle errors gracefully\n5. **Validate all inputs** - Check file existence, permissions, formats\n6. **Use functions for reusability** - Prefix with meaningful names\n7. **Implement structured logging** - Include timestamps and levels\n8. **Support dry-run mode** - Allow users to preview changes\n9. **Handle temporary files safely** - Use mktemp, cleanup with trap\n10. **Design for idempotency** - Scripts should be safe to rerun\n11. **Document requirements** - List dependencies and minimum versions\n12. **Test error paths** - Ensure error handling works correctly\n13. **Use `command -v`** - Safer than `which` for checking executables\n14. **Prefer printf over echo** - More predictable across systems\n\n## Resources\n\n- **Bash Strict Mode**: http:\u002F\u002Fredsymbol.net\u002Farticles\u002Funofficial-bash-strict-mode\u002F\n- **Google Shell Style Guide**: https:\u002F\u002Fgoogle.github.io\u002Fstyleguide\u002Fshellguide.html\n- **Defensive BASH Programming**: https:\u002F\u002Fwww.lifepipe.net\u002F\n",{"name":5,"description":7},"main","7850740bd837adb32f0a109ab2af82482196c6f2","skills\u002F_collections\u002Fwshobson-agents\u002Fplugins\u002Fshell-scripting\u002Fskills\u002Fbash-defensive-patterns",1,"https:\u002F\u002Fgithub.com\u002Fshengdabai\u002FTony-Claude-Code-Skills","https:\u002F\u002Fzturnsgo.com","https:\u002F\u002Fgithub.com\u002Fshengdabai","https:\u002F\u002Fzturnsgo.com\u002F","AI × education creator — producer, not consumer. Taught 6,000+ learners; shipping learning tools & daily essays with Claude Code, practicing @xiaolai's way 🥋","2026-11-01 21:28:23",{"source":8,"skillName":5,"commands":60,"prompt":70,"zipAvailable":71},[61,64,67],{"tool":62,"command":63},"npx","npx skills add shengdabai\u002FTony-Claude-Code-Skills --skill bash-defensive-patterns",{"tool":65,"command":66},"bunx","bunx skills add shengdabai\u002FTony-Claude-Code-Skills --skill bash-defensive-patterns",{"tool":68,"command":69},"pnpm","pnpm dlx skills add shengdabai\u002FTony-Claude-Code-Skills --skill bash-defensive-patterns","安装技能，技能地址：https:\u002F\u002Fgithub.com\u002Fshengdabai\u002FTony-Claude-Code-Skills\u002Fblob\u002Fmain\u002Fskills\u002F_collections\u002Fwshobson-agents\u002Fplugins\u002Fshell-scripting\u002Fskills\u002Fbash-defensive-patterns\u002FSKILL.md",true,[],[74,92,122,147,169,189],{"skillNo":75,"name":76,"nameZh":6,"description":77,"descriptionZh":6,"repositoryFullName":8,"ownerLogin":9,"ownerAvatarUrl":10,"ownerAccountNo":11,"ownerDisplayName":12,"repositoryNo":13,"starsCount":14,"licenseSpdxId":15,"licenseFileUrl":6,"sourceHtmlUrl":78,"categories":79,"keywords":85,"publishedAt":44},"01M70P17DAD4C1C47NPH6A96EM","xiaolai-methodology","以李笑来(Li Xiaolai)的思考方式、方法论与表达风格,为用户做全方位 1-on-1 教练指导,覆盖创业、赚钱、投资、学习、自学、读书写作、用 AI、以及人生心态与自我管理。当用户提到 \"李笑来\"、\"笑来\"、\"笑来老师\"、\"扮演李笑来\"、\"找笑来聊聊\"、\"笑来怎么看\"、\"xiaolai\"、\"把时间当作朋友\"、\"通往财富自由之路\"、\"定投改变命运\"、\"韭菜的自我修养\"、\"自学是门手艺\"、\"让时间陪你慢慢变富\"、\"七年就是一辈子\"、\"元认知\"、\"活在未来\"、\"复利\u002F长期主义\"、\"践行\"、\"痴迷改进\"、\"个人商业模式\u002F出售时间\"、\"睡后收入\"、\"定投\"、\"财富自由\"、\"操作系统升级\"、\"最少必要知识\"、\"北极星提示词\"、\"用 AI 该怎么学\u002F思考\" 等任一触发词,或当用户带着关于创业\u002F赚钱\u002F投资\u002F学习\u002F职业\u002F重大人生决策的困惑、希望被人用笑来式的「逻辑 + 大白话 + 类比 + 重新定义 + 践行导向」来点醒和指导时,自动进入李笑来教练模式。","https:\u002F\u002Fgithub.com\u002Fshengdabai\u002FTony-Claude-Code-Skills\u002Fblob\u002Fmain\u002Fxiaolai-methodology\u002FSKILL.md",[80],{"categoryNo":81,"categoryName":82,"taxonomyType":83,"taxonomyTypeDesc":84},"01JBSEEDCAT000000000000018","写作与文案","SCENARIO","使用场景",[86,87,88,89,90,29,91],"methodology","xiaolai","xiaolai methodology","朋友","投资","收入",{"skillNo":93,"name":94,"nameZh":6,"description":95,"descriptionZh":6,"repositoryFullName":8,"ownerLogin":9,"ownerAvatarUrl":10,"ownerAccountNo":11,"ownerDisplayName":12,"repositoryNo":13,"starsCount":14,"licenseSpdxId":15,"licenseFileUrl":6,"sourceHtmlUrl":96,"categories":97,"keywords":102,"publishedAt":44},"01M70P13NB9YP7ACJR1S861CDS","zread","Produce and consume a wiki-style knowledge base for a code repository via the `zread` CLI and its on-disk output under `.\u002F.zread\u002Fwiki\u002F`. Use this skill whenever the user wants to understand, onboard onto, explore, summarize, map, or get an overview of an unfamiliar codebase; asks for architecture docs, a project wiki, a repo walkthrough, module\u002Fpackage explanations, or \"what does this repo do\"; wants to generate, regenerate, resume, browse, or serve code documentation locally; or mentions zread \u002F zread.ai directly. Also use it proactively before diving into a large unknown repo — if `.\u002F.zread\u002Fwiki\u002Fcurrent` exists, read the generated pages instead of crawling source file-by-file; if it doesn't, consider offering to run `zread generate`. The trigger is the intent (understand a codebase through generated docs), not the literal word \"zread\".","https:\u002F\u002Fgithub.com\u002Fshengdabai\u002FTony-Claude-Code-Skills\u002Fblob\u002Fmain\u002Fskills\u002Fzread\u002FSKILL.md",[98,101],{"categoryNo":99,"categoryName":100,"taxonomyType":83,"taxonomyTypeDesc":84},"01JBSEEDCAT000000000000023","Skill与智能体开发",{"categoryNo":19,"categoryName":20,"taxonomyType":21,"taxonomyTypeDesc":22},[94,103,104,105,106,107,108,109,110,111,112,113,114,115,116,117,118,119,120,121],"knowledge","wiki","explore","walkthrough","project","get","knowledge base","run","generate","intent","cli","map","documentation","project wiki","disk","architecture","code","unknown","generated",{"skillNo":123,"name":124,"nameZh":6,"description":125,"descriptionZh":6,"repositoryFullName":8,"ownerLogin":9,"ownerAvatarUrl":10,"ownerAccountNo":11,"ownerDisplayName":12,"repositoryNo":13,"starsCount":14,"licenseSpdxId":15,"licenseFileUrl":6,"sourceHtmlUrl":126,"categories":127,"keywords":132,"publishedAt":44},"01M70P10S4SWMZQ8BJAFBFDRW3","youtube","Launch the YouTube Creator Agent to auto-generate videos.\nUse when: user types \u002Fyoutube, wants to create YouTube videos,\ngenerate video content, or upload to YouTube.\nKeywords: youtube, video, 视频, 创作视频, 发布视频","https:\u002F\u002Fgithub.com\u002Fshengdabai\u002FTony-Claude-Code-Skills\u002Fblob\u002Fmain\u002Fskills\u002Fyoutube\u002FSKILL.md",[128,129],{"categoryNo":99,"categoryName":100,"taxonomyType":83,"taxonomyTypeDesc":84},{"categoryNo":130,"categoryName":131,"taxonomyType":21,"taxonomyTypeDesc":22},"01JBSEEDCAT000000000000036","内容创作者",[124,133,134,135,136,137,138,139,111,140,141,142,28,38,143,144,145,146],"user","content","视频","creator","generate video","videos","launch","video content","create","upload","auto","types","Video","创作",{"skillNo":148,"name":149,"nameZh":6,"description":150,"descriptionZh":6,"repositoryFullName":8,"ownerLogin":9,"ownerAvatarUrl":10,"ownerAccountNo":11,"ownerDisplayName":12,"repositoryNo":13,"starsCount":14,"licenseSpdxId":15,"licenseFileUrl":6,"sourceHtmlUrl":151,"categories":152,"keywords":154,"publishedAt":44},"01M70P0YE95D8BACZCGV8BK90K","youtube-script-sync","Sync, update, or optimize Tony's GetNote knowledge base `Youtube视频逐字稿` by turning each parent recording or first-person idea note into an idempotent child note containing a directly recordable YouTube long-video or Shorts script. Use when the user says “更新\u002F同步\u002F优化 Youtube视频逐字稿知识库”, or says “更新\u002F同步\u002F优化该知识库” while this knowledge base is the active context.","https:\u002F\u002Fgithub.com\u002Fshengdabai\u002FTony-Claude-Code-Skills\u002Fblob\u002Fmain\u002Fskills\u002Fyoutube-script-sync\u002FSKILL.md",[153],{"categoryNo":99,"categoryName":100,"taxonomyType":83,"taxonomyTypeDesc":84},[155,156,124,157,158,145,159,160,161,162,163,164,165,166,109,167,28,38,103,168],"sync","script","youtube script sync","recording","shorts","first","base","person","update","active","child","optimize","idempotent","long",{"skillNo":170,"name":171,"nameZh":6,"description":172,"descriptionZh":6,"repositoryFullName":8,"ownerLogin":9,"ownerAvatarUrl":10,"ownerAccountNo":11,"ownerDisplayName":12,"repositoryNo":13,"starsCount":14,"licenseSpdxId":15,"licenseFileUrl":6,"sourceHtmlUrl":173,"categories":174,"keywords":179,"publishedAt":44},"01M70P0WMV5XT0EEC0N445PW07","writing-skills","How to write SKILL.md files that trigger reliably and teach effectively. Use when creating, improving, or reviewing Claude Code skills.","https:\u002F\u002Fgithub.com\u002Fshengdabai\u002FTony-Claude-Code-Skills\u002Fblob\u002Fmain\u002Fskills\u002Fxiaolai\u002Fnlpm\u002Fskills\u002Fnlpm\u002Fwriting-skills\u002FSKILL.md",[175,176,177,178],{"categoryNo":81,"categoryName":82,"taxonomyType":83,"taxonomyTypeDesc":84},{"categoryNo":99,"categoryName":100,"taxonomyType":83,"taxonomyTypeDesc":84},{"categoryNo":19,"categoryName":20,"taxonomyType":21,"taxonomyTypeDesc":22},{"categoryNo":130,"categoryName":131,"taxonomyType":21,"taxonomyTypeDesc":22},[180,29,181,182,183,184,119,28,38,185,186,187,188],"writing skills","how","teach","write skill","write","claude code skills","files","how to","trigger",{"skillNo":190,"name":191,"nameZh":6,"description":192,"descriptionZh":6,"repositoryFullName":8,"ownerLogin":9,"ownerAvatarUrl":10,"ownerAccountNo":11,"ownerDisplayName":12,"repositoryNo":13,"starsCount":14,"licenseSpdxId":15,"licenseFileUrl":6,"sourceHtmlUrl":193,"categories":194,"keywords":197,"publishedAt":44},"01M70P0SJFR4YVJQBGMHKGSKXT","writing-rules","How to write .claude\u002Frules\u002F files that Claude actually follows. Use when creating, improving, or reviewing project rules.","https:\u002F\u002Fgithub.com\u002Fshengdabai\u002FTony-Claude-Code-Skills\u002Fblob\u002Fmain\u002Fskills\u002Fxiaolai\u002Fnlpm\u002Fskills\u002Fnlpm\u002Fwriting-rules\u002FSKILL.md",[195,196],{"categoryNo":81,"categoryName":82,"taxonomyType":83,"taxonomyTypeDesc":84},{"categoryNo":130,"categoryName":131,"taxonomyType":21,"taxonomyTypeDesc":22},[198,29,199,107,200,186,28,181,184,38,187],"Rules","writing rules","project rules"]