Bash Scripting Mastery Scope and platform contract This skill targets Bash itself , wherever Bash runs - Linux, macOS, WSL, Git Bash / MSYS2 on Windows, and Bash-based container images. It does not cover native PowerShell : a PowerShell script is a different language and should use . On Windows, assumes the user is running Bash inside Git Bash, WSL, or a similar Bash environment, and addresses the MSYS path-translation quirks that result. Repository conventions Project-level conventions (Windows backslashes in tool calls, documentation discipline, etc.) live in the agent body and the plugin.…

\\n\\t' # Safe word splitting\n# Run shellcheck your_script.sh before deployment.\n# Test on every target platform before production.\n```\n\n**Bash-portability quick check:**\n\n```bash\n# Linux/macOS: Full bash features\n# Git Bash (Windows): Most features, some system calls missing (no systemd, /proc differs)\n# WSL: Effectively Linux; /mnt/c for Windows filesystem\n# Containers: Depends on base image - alpine ships /bin/sh, not bash\n# POSIX mode: Use /bin/sh and avoid bashisms\n```\n\n## When to use this skill\n\n**Always activate for:**\n\n- Writing or modifying any bash/shell script\n- Reviewing or refactoring existing scripts\n- Debugging shell script failures\n- DevOps automation, CI/CD pipelines, system administration\n- Cross-environment Bash portability (Linux \u003c-> macOS \u003c-> WSL \u003c-> Git Bash \u003c-> container)\n\n**Do not use this skill for:**\n\n- PowerShell scripts - use `powershell-master`\n- Batch (`.cmd`/`.bat`) scripting\n- Generic command help unrelated to scripting\n\n## Core principles\n\n### 1. Safety first\n\nEvery script should open with the safety preamble:\n\n```bash\n#!/usr/bin/env bash\nset -e # Exit on any error\nset -u # Exit on undefined variable\nset -o pipefail # Catch failures mid-pipeline\nset -E # Inherit ERR trap into functions\nIFS=

Bash Scripting Mastery Scope and platform contract This skill targets Bash itself , wherever Bash runs - Linux, macOS, WSL, Git Bash / MSYS2 on Windows, and Bash-based container images. It does not cover native PowerShell : a PowerShell script is a different language and should use . On Windows, assumes the user is running Bash inside Git Bash, WSL, or a similar Bash environment, and addresses the MSYS path-translation quirks that result. Repository conventions Project-level conventions (Windows backslashes in tool calls, documentation discipline, etc.) live in the agent body and the plugin.…

\\n\\t' # Avoid word splitting on spaces\n\nreadonly SCRIPT_DIR=\"$(cd \"$(dirname \"${BASH_SOURCE[0]}\")\" && pwd)\"\nreadonly SCRIPT_NAME=\"$(basename \"${BASH_SOURCE[0]}\")\"\n```\n\n### 2. POSIX vs Bash\n\n| Need to run on any UNIX `sh` | `#!/bin/sh`, no `[[ ]]`, no arrays, no process substitution |\n|--|--|\n| Modern Linux/macOS with Bash | `#!/usr/bin/env bash`, prefer `[[ ]]`, arrays, regex |\n| Alpine/minimal containers | Either install bash explicitly or write POSIX-compliant `sh` |\n\n### 3. Quoting\n\n```bash\n# Always quote expansions\nprocess \"$file_path\" # correct\nprocess $file_path # word-splitting bug\n\n# Arrays\nfiles=(\"file 1.txt\" \"file 2.txt\")\nprocess \"${files[@]}\" # each element kept separate\nprocess \"${files[*]}\" # joined as one string - usually wrong\n```\n\n### 4. ShellCheck\n\nRun `shellcheck` on every script. Only disable warnings with a justification comment: `# shellcheck disable=SC2086 reason: intentional word splitting`.\n\nSee `references/best_practices.md` for the full quoting/style table and `references/patterns_antipatterns.md` for the common pitfalls.\n\n## Platform-specific considerations\n\n### Git Bash / MSYS2 (Windows)\n\nGit Bash auto-converts Unix-style arguments to Windows paths. This is the largest single source of cross-platform Bash bugs on Windows.\n\n```bash\n# The conversion: /foo becomes C:/Program Files/Git/usr/foo\n# Disable per-command:\nMSYS_NO_PATHCONV=1 command /path/that/should/stay/unix\n\n# Manual conversion\nunix_path=$(cygpath -u \"C:\\Windows\\System32\")\nwin_path=$(cygpath -w \"/c/Users/username\")\n\n# Detect Git Bash\nif [[ \"$OSTYPE\" == \"msys\" ]] || [[ \"$OSTYPE\" == \"mingw\"* ]]; then\n : # Git Bash\nfi\ncase \"${MSYSTEM:-}\" in\n MINGW64|MINGW32|MSYS) : ;; # MSYS2 / Git Bash environment\nesac\n\n# Flags that look like paths\ncommand //e //s # double-slash to suppress conversion\ncommand -e -s # or use dash-options\n```\n\nFull Git Bash + Windows path notes live in `references/windows-git-bash-paths.md`.\n\n### Linux\n\nGNU coreutils, `/proc`, systemd integration. Detect via `[[ \"$OSTYPE\" == \"linux-gnu\"* ]]`.\n\n### macOS\n\nBSD utilities behave differently from GNU. Most common gotchas: `sed -i ''` (empty string required), `date` flags differ, `readlink -f` not available on stock macOS.\n\n```bash\nif command -v gsed >/dev/null; then SED=gsed; else SED=sed; fi\n```\n\n### WSL\n\nEffectively Linux. The Windows filesystem is mounted at `/mnt/c/`. Detect via `grep -qi microsoft /proc/version`.\n\n### Containers\n\nAlpine images ship only `/bin/sh` (BusyBox). Write POSIX-compliant scripts or `apk add bash`. Container init quirks: PID 1 must reap children and handle signals. Detect via `[ -f /.dockerenv ]` or `[ -n \"$KUBERNETES_SERVICE_HOST\" ]`.\n\n### Portable platform-detection template\n\n```bash\ndetect_platform() {\n case \"$OSTYPE\" in\n linux-gnu*) echo \"linux\" ;;\n darwin*) echo \"macos\" ;;\n msys*|cygwin*) echo \"windows\" ;;\n *) echo \"unknown\" ;;\n esac\n}\n```\n\nFull per-platform tables (BSD-vs-GNU coreutils flags, WSL networking, container init patterns) live in `references/platform_specifics.md`.\n\n## Best practices (summary)\n\nThe full patterns - function design, error handling, input validation, argument parsing, logging - live in `references/in-depth-patterns.md`. The headline rules:\n\n- One concern per function; locals declared first; validate input; return non-zero on error.\n- Constants `UPPER_CASE`; locals `lower_case`; mark immutable values `readonly`.\n- Always check exit codes (`if ! cmd`, `||`, traps, or a central `error_exit` helper).\n- Validate every external input - empty, format, length, charset.\n- Use `getopts` or a `case`-based argument parser; print usage and exit 1 on bad input.\n- Use a leveled logger that writes to stderr.\n\n## Security, performance, testing, debugging, advanced patterns\n\nThese each have dedicated sections in `references/in-depth-patterns.md`:\n\n| Topic | What it covers |\n|--|--|\n| Security | Command-injection prevention, path-traversal guards, privilege management, secure temp files |\n| Performance | Avoiding subshells, bash built-ins vs externals, process substitution, array ops |\n| Testing | BATS unit tests, integration test patterns, CI/CD wiring |\n| Debugging | `set -x`, `PS4`, conditional debug helpers, tracing and profiling |\n| Advanced patterns | Safe config parsing, parallel processing, signal handling, retries with backoff |\n\nRead that reference any time you need the canonical code template for one of those topics.\n\n## Reference files\n\n- [`references/platform_specifics.md`](references/platform_specifics.md) - Detailed platform differences and workarounds\n- [`references/best_practices.md`](references/best_practices.md) - Comprehensive industry standards and guidelines\n- [`references/patterns_antipatterns.md`](references/patterns_antipatterns.md) - Common patterns and pitfalls with solutions\n- [`references/windows-git-bash-paths.md`](references/windows-git-bash-paths.md) - Git Bash / MSYS path-translation reference\n- [`references/in-depth-patterns.md`](references/in-depth-patterns.md) - Function design, security, performance, testing, debugging, advanced patterns\n- [`references/resources.md`](references/resources.md) - Official docs, style guides, tooling, and learning links\n\n## Success criteria\n\nA Bash script written with this skill should:\n\n1. Pass `shellcheck` with no warnings\n2. Begin with `set -euo pipefail`\n3. Quote every variable expansion\n4. Print usage on `-h`/`--help`\n5. Decompose into testable functions\n6. Handle empty input, missing files, and unexpected arguments\n7. Run on every target platform (Linux/macOS/WSL/Git Bash/container) where it claims support\n8. Match the Google Shell Style Guide\n9. Clean up on exit (`trap EXIT`)\n10. Be unit-tested with BATS where logic is non-trivial\n\n```bash\n# Pre-deployment checklist\nshellcheck script.sh\nbash -n script.sh\nbats test/script.bats\n./script.sh --help\nDEBUG=true ./script.sh\n```\n\n## Troubleshooting\n\n### Script fails on a different platform\n\n- `checkbashisms script.sh` to surface non-portable constructs.\n- `command -v tool` to verify a required tool is installed.\n- Diff command flags between GNU and BSD (`sed --version` etc.).\n\n### ShellCheck warnings\n\n- Read the rule explanation (`shellcheck -W SC2086`).\n- Fix the underlying issue; only disable a rule with a justification comment.\n\n### Works interactively but fails in cron\n\n- Cron has a minimal `PATH` - set `PATH` explicitly.\n- Use absolute paths.\n- Redirect stdout/stderr: `./script.sh >> /tmp/cron.log 2>&1`.\n\n### Performance issues\n\n- Profile with `time`.\n- Enable `set -x` to find slow steps.\n- Replace external invocations with Bash built-ins where possible.\n---","attachment_filenames":["references/best_practices.md","references/in-depth-patterns.md","references/patterns_antipatterns.md","references/platform_specifics.md","references/resources.md","references/windows-git-bash-paths.md"],"attachments":[{"filename":"references/best_practices.md","content":"# Bash Scripting Best Practices & Industry Standards\n\nComprehensive guide to professional bash scripting following industry standards including Google Shell Style Guide, ShellCheck recommendations, and community best practices.\n\n---\n\n## Table of Contents\n\n1. [Script Structure](#script-structure)\n2. [Safety and Robustness](#safety-and-robustness)\n3. [Style Guidelines](#style-guidelines)\n4. [Functions](#functions)\n5. [Variables](#variables)\n6. [Error Handling](#error-handling)\n7. [Input/Output](#inputoutput)\n8. [Security](#security)\n9. [Performance](#performance)\n10. [Documentation](#documentation)\n11. [Testing](#testing)\n12. [Maintenance](#maintenance)\n\n---\n\n## 🚨 CRITICAL GUIDELINES\n\n### Windows File Path Requirements\n\n**MANDATORY: Always Use Backslashes on Windows for File Paths**\n\nWhen using Edit or Write tools on Windows, you MUST use backslashes (`\\`) in file paths, NOT forward slashes (`/`).\n\n**Examples:**\n- ❌ WRONG: `D:/repos/project/file.tsx`\n- ✅ CORRECT: `D:\\repos\\project\\file.tsx`\n\nThis applies to:\n- Edit tool file_path parameter\n- Write tool file_path parameter\n- All file operations on Windows systems\n\n\n### Documentation Guidelines\n\n**NEVER create new documentation files unless explicitly requested by the user.**\n\n- **Priority**: Update existing README.md files rather than creating new documentation\n- **Repository cleanliness**: Keep repository root clean - only README.md unless user requests otherwise\n- **Style**: Documentation should be concise, direct, and professional - avoid AI-generated tone\n- **User preference**: Only create additional .md files when user specifically asks for documentation\n\n\n---\n\n## Script Structure\n\n### Standard Template\n\n```bash\n#!/usr/bin/env bash\n#\n# Script Name: script_name.sh\n# Description: Brief description of what this script does\n# Author: Your Name\n# Date: 2024-01-01\n# Version: 1.0.0\n#\n# Usage: script_name.sh [OPTIONS] \u003carguments>\n#\n# Options:\n# -h, --help Show help message\n# -v, --verbose Enable verbose output\n#\n# Dependencies:\n# - bash >= 4.0\n# - jq\n# - curl\n#\n# Exit Codes:\n# 0 - Success\n# 1 - General error\n# 2 - Invalid arguments\n# 3 - Missing dependency\n#\n\nset -euo pipefail\nIFS=

Bash Scripting Mastery Scope and platform contract This skill targets Bash itself , wherever Bash runs - Linux, macOS, WSL, Git Bash / MSYS2 on Windows, and Bash-based container images. It does not cover native PowerShell : a PowerShell script is a different language and should use . On Windows, assumes the user is running Bash inside Git Bash, WSL, or a similar Bash environment, and addresses the MSYS path-translation quirks that result. Repository conventions Project-level conventions (Windows backslashes in tool calls, documentation discipline, etc.) live in the agent body and the plugin.…

\\n\\t'\n\n# Script metadata\nreadonly SCRIPT_DIR=\"$(cd \"$(dirname \"${BASH_SOURCE[0]}\")\" && pwd)\"\nreadonly SCRIPT_NAME=\"$(basename \"${BASH_SOURCE[0]}\")\"\nreadonly SCRIPT_VERSION=\"1.0.0\"\n\n# Global constants\nreadonly DEFAULT_TIMEOUT=30\nreadonly CONFIG_FILE=\"${CONFIG_FILE:-$SCRIPT_DIR/config.conf}\"\n\n# Global variables\nVERBOSE=false\nDRY_RUN=false\n\n#------------------------------------------------------------------------------\n# Functions\n#------------------------------------------------------------------------------\n\n# Show usage information\nusage() {\n cat \u003c\u003cEOF\nUsage: $SCRIPT_NAME [OPTIONS] \u003ccommand>\n\nDescription of what the script does.\n\nOPTIONS:\n -h, --help Show this help message\n -v, --verbose Enable verbose output\n -n, --dry-run Show what would be done without doing it\n -V, --version Show version\n\nCOMMANDS:\n build Build the project\n test Run tests\n deploy Deploy to production\n\nEXAMPLES:\n $SCRIPT_NAME build\n $SCRIPT_NAME --verbose test\n $SCRIPT_NAME deploy --dry-run\n\nEOF\n}\n\n# Cleanup function\ncleanup() {\n local exit_code=$?\n # Remove temporary files\n [[ -n \"${TEMP_DIR:-}\" ]] && rm -rf \"$TEMP_DIR\"\n exit \"$exit_code\"\n}\n\n# Main function\nmain() {\n # Parse arguments\n parse_arguments \"$@\"\n\n # Validate dependencies\n check_dependencies\n\n # Main script logic here\n echo \"Script execution complete\"\n}\n\n#------------------------------------------------------------------------------\n# Script execution\n#------------------------------------------------------------------------------\n\n# Set up cleanup trap\ntrap cleanup EXIT INT TERM\n\n# Run main function with all arguments\nmain \"$@\"\n```\n\n### File Organization\n\n```bash\n# For larger projects, organize code into modules\n\n# project/\n# ├── bin/\n# │ └── main.sh # Entry point\n# ├── lib/\n# │ ├── common.sh # Shared utilities\n# │ ├── config.sh # Configuration handling\n# │ └── logger.sh # Logging functions\n# ├── config/\n# │ └── default.conf # Default configuration\n# ├── test/\n# │ ├── test_common.bats # Unit tests\n# │ └── test_config.bats\n# └── README.md\n\n# In main.sh:\n# Source library files\nreadonly LIB_DIR=\"$(cd \"$(dirname \"${BASH_SOURCE[0]}\")/../lib\" && pwd)\"\n\n# shellcheck source=lib/common.sh\nsource \"$LIB_DIR/common.sh\"\n# shellcheck source=lib/logger.sh\nsource \"$LIB_DIR/logger.sh\"\n```\n\n---\n\n## Safety and Robustness\n\n### Essential Safety Settings\n\n```bash\n# ALWAYS use these at the start of scripts\nset -e # Exit immediately if a command exits with a non-zero status\nset -u # Treat unset variables as an error\nset -o pipefail # Return value of a pipeline is status of last command to exit with non-zero status\nset -E # ERR trap is inherited by shell functions\n\n# Optionally add:\nset -x # Print commands before executing (debugging)\nset -C # Prevent output redirection from overwriting existing files\n```\n\n### Safe Word Splitting\n\n```bash\n# Default IFS causes issues with filenames containing spaces\n# OLD IFS: space, tab, newline\nIFS=

Bash Scripting Mastery Scope and platform contract This skill targets Bash itself , wherever Bash runs - Linux, macOS, WSL, Git Bash / MSYS2 on Windows, and Bash-based container images. It does not cover native PowerShell : a PowerShell script is a different language and should use . On Windows, assumes the user is running Bash inside Git Bash, WSL, or a similar Bash environment, and addresses the MSYS path-translation quirks that result. Repository conventions Project-level conventions (Windows backslashes in tool calls, documentation discipline, etc.) live in the agent body and the plugin.…

\\t\\n'\n\n# SAFE IFS: only tab and newline\nIFS=

Bash Scripting Mastery Scope and platform contract This skill targets Bash itself , wherever Bash runs - Linux, macOS, WSL, Git Bash / MSYS2 on Windows, and Bash-based container images. It does not cover native PowerShell : a PowerShell script is a different language and should use . On Windows, assumes the user is running Bash inside Git Bash, WSL, or a similar Bash environment, and addresses the MSYS path-translation quirks that result. Repository conventions Project-level conventions (Windows backslashes in tool calls, documentation discipline, etc.) live in the agent body and the plugin.…

\\n\\t'\n\n# This prevents word splitting on spaces, which is a common source of bugs:\nfiles=\"file1.txt file2.txt\"\nfor file in $files; do # Without proper IFS, this splits on spaces!\n echo \"$file\"\ndone\n```\n\n### Quoting Rules\n\n```bash\n# ALWAYS quote variable expansions\ncommand \"$variable\" # ✓ CORRECT\ncommand $variable # ✗ WRONG (word splitting and globbing)\n\n# Arrays: Proper expansion\nfiles=(\"file1.txt\" \"file 2.txt\" \"file 3.txt\")\nprocess \"${files[@]}\" # ✓ CORRECT (each element separate)\nprocess \"${files[*]}\" # ✗ WRONG (all elements as one string)\nprocess ${files[@]} # ✗ WRONG (unquoted, word splitting)\n\n# Command substitution: Quote the result\nresult=\"$(command)\" # ✓ CORRECT\nresult=$(command) # ✗ WRONG (unless word splitting is desired)\n\n# Glob patterns: Don't quote when you want globbing\nfor file in *.txt; do # ✓ CORRECT (globbing intended)\n echo \"$file\" # ✓ CORRECT (no globbing inside)\ndone\n\nfor file in \"*.txt\"; do # ✗ WRONG (literal \"*.txt\", no globbing)\n echo \"$file\"\ndone\n```\n\n### Handling Special Characters\n\n```bash\n# Filenames with special characters\n# Use quotes and proper escaping\n\n# Create array from find output\nmapfile -t files \u003c \u003c(find . -name \"*.txt\" -print0 | xargs -0)\n\n# Or modern bash:\nfiles=()\nwhile IFS= read -r -d '' file; do\n files+=(\"$file\")\ndone \u003c \u003c(find . -name \"*.txt\" -print0)\n\n# Process files safely\nfor file in \"${files[@]}\"; do\n [[ -f \"$file\" ]] && process \"$file\"\ndone\n```\n\n---\n\n## Style Guidelines\n\nBased on Google Shell Style Guide and community standards.\n\n### Naming Conventions\n\n```bash\n# Constants: UPPER_CASE with underscores\nreadonly MAX_RETRIES=3\nreadonly DEFAULT_TIMEOUT=30\nreadonly CONFIG_DIR=\"/etc/myapp\"\n\n# Environment variables: UPPER_CASE (by convention)\nexport DATABASE_URL=\"postgres://localhost/db\"\nexport LOG_LEVEL=\"INFO\"\n\n# Global variables: UPPER_CASE or lower_case (be consistent in your project)\nGLOBAL_COUNTER=0\ncurrent_state=\"initialized\"\n\n# Local variables: lower_case with underscores\nlocal user_name=\"john\"\nlocal file_count=0\nlocal error_message=\"\"\n\n# Functions: lower_case with underscores\nfunction_name() {\n local var=\"value\"\n}\n\n# Private functions: Prefix with underscore\n_internal_function() {\n # Helper function not meant to be called externally\n}\n```\n\n### Indentation and Formatting\n\n```bash\n# Use 4 spaces for indentation (not tabs)\n# Or 2 spaces (be consistent)\n\n# Function definition\nmy_function() {\n local arg=\"$1\"\n\n if [[ -n \"$arg\" ]]; then\n echo \"Processing $arg\"\n else\n echo \"No argument provided\"\n return 1\n fi\n\n return 0\n}\n\n# Conditional blocks\nif [[ condition ]]; then\n # code\nelif [[ other_condition ]]; then\n # code\nelse\n # code\nfi\n\n# Loops\nfor item in \"${array[@]}\"; do\n # code\ndone\n\nwhile [[ condition ]]; do\n # code\ndone\n\n# Case statement\ncase \"$variable\" in\n pattern1)\n # code\n ;;\n pattern2)\n # code\n ;;\n *)\n # default\n ;;\nesac\n\n# Line length: Prefer \u003c 80 characters, max 100\n# Break long lines with backslash\nlong_command \\\n --option1 value1 \\\n --option2 value2 \\\n --option3 value3\n\n# Or use arrays for readability\ncommand_args=(\n --option1 value1\n --option2 value2\n --option3 value3\n)\ncommand \"${command_args[@]}\"\n```\n\n### Comments\n\n```bash\n# Single-line comments: Start with # followed by space\n# This is a comment\n\n# Function documentation (before function definition)\n#######################################\n# Description of what this function does\n# Globals:\n# GLOBAL_VAR - Description\n# Arguments:\n# $1 - First argument description\n# $2 - Second argument description (optional)\n# Outputs:\n# Writes result to stdout\n# Returns:\n# 0 on success, non-zero on error\n#######################################\nmy_function() {\n # Implementation\n}\n\n# Inline comments: Use sparingly, only when necessary\nresult=$(complex_calculation) # Result in milliseconds\n\n# TODO comments\n# TODO(username): Description of what needs to be done\n# FIXME(username): Description of what needs to be fixed\n# HACK(username): Description of workaround and why it's needed\n\n# Section separators for long scripts\n#------------------------------------------------------------------------------\n# Configuration Section\n#------------------------------------------------------------------------------\n\n#######################################\n# Database Functions\n#######################################\n```\n\n### Test Constructs\n\n```bash\n# Prefer [[ ]] over [ ] for tests in bash\n# [[ ]] is a bash keyword with better behavior:\n# - No word splitting\n# - No pathname expansion\n# - More operators available\n\n# String comparison\nif [[ \"$string1\" == \"$string2\" ]]; then # ✓ CORRECT\nif [ \"$string1\" = \"$string2\" ]; then # ✓ CORRECT (POSIX)\nif [ $string1 == $string2 ]; then # ✗ WRONG (word splitting, not POSIX)\n\n# String matching with patterns\nif [[ \"$file\" == *.txt ]]; then # ✓ CORRECT (pattern matching)\nif [[ \"$file\" =~ \\.txt$ ]]; then # ✓ CORRECT (regex)\n\n# Numeric comparison\nif [[ $num -gt 10 ]]; then # ✓ CORRECT\nif (( num > 10 )); then # ✓ CORRECT (arithmetic context)\n\n# File tests\nif [[ -f \"$file\" ]]; then # ✓ CORRECT (regular file)\nif [[ -d \"$dir\" ]]; then # ✓ CORRECT (directory)\nif [[ -e \"$path\" ]]; then # ✓ CORRECT (exists)\nif [[ -r \"$file\" ]]; then # ✓ CORRECT (readable)\nif [[ -w \"$file\" ]]; then # ✓ CORRECT (writable)\nif [[ -x \"$file\" ]]; then # ✓ CORRECT (executable)\n\n# Logical operators\nif [[ condition1 && condition2 ]]; then # ✓ CORRECT (AND)\nif [[ condition1 || condition2 ]]; then # ✓ CORRECT (OR)\nif [[ ! condition ]]; then # ✓ CORRECT (NOT)\n\n# Empty/non-empty string\nif [[ -z \"$var\" ]]; then # ✓ CORRECT (empty)\nif [[ -n \"$var\" ]]; then # ✓ CORRECT (non-empty)\n```\n\n---\n\n## Functions\n\n### Function Best Practices\n\n```bash\n# Good function structure\nprocess_file() {\n # 1. Declare local variables\n local file=\"$1\"\n local output_dir=\"${2:-.}\" # Default to current directory\n local result=\"\"\n\n # 2. Input validation\n if [[ ! -f \"$file\" ]]; then\n echo \"Error: File not found: $file\" >&2\n return 1\n fi\n\n if [[ ! -d \"$output_dir\" ]]; then\n echo \"Error: Output directory not found: $output_dir\" >&2\n return 1\n fi\n\n # 3. Main logic\n result=$(perform_operation \"$file\")\n\n # 4. Output\n echo \"$result\" > \"$output_dir/result.txt\"\n\n # 5. Return status\n return 0\n}\n\n# Use return codes to indicate success/failure\n# 0 = success, non-zero = error\nvalidate_input() {\n local input=\"$1\"\n\n if [[ ! \"$input\" =~ ^[a-zA-Z0-9]+$ ]]; then\n return 1 # Invalid input\n fi\n\n return 0 # Valid input\n}\n\n# Usage\nif validate_input \"$user_input\"; then\n process \"$user_input\"\nelse\n echo \"Invalid input\" >&2\n exit 1\nfi\n```\n\n### Function Documentation\n\n```bash\n#######################################\n# Process a file and generate output\n# Globals:\n# OUTPUT_FORMAT - Output format (json/xml/csv)\n# Arguments:\n# $1 - Input file path (required)\n# $2 - Output directory (optional, default: .)\n# Outputs:\n# Writes processed data to stdout\n# Writes result file to output directory\n# Returns:\n# 0 on success\n# 1 if file not found\n# 2 if processing fails\n# Example:\n# process_file \"input.txt\" \"/tmp/output\"\n#######################################\nprocess_file() {\n # Implementation\n}\n```\n\n### Local Variables\n\n```bash\n# ALWAYS use local for function variables\nbad_function() {\n counter=0 # ✗ WRONG - Global variable!\n}\n\ngood_function() {\n local counter=0 # ✓ CORRECT - Local to function\n}\n\n# Declare local before assignment\ngood_practice() {\n local result\n result=$(command_that_might_fail) || return 1\n echo \"$result\"\n}\n\n# This won't catch command failure:\nbad_practice() {\n local result=$(command_that_might_fail) # ✗ WRONG\n echo \"$result\"\n}\n```\n\n---\n\n## Variables\n\n### Variable Declaration\n\n```bash\n# Readonly for constants\nreadonly MAX_RETRIES=3\ndeclare -r MAX_RETRIES=3 # Alternative syntax\n\n# Arrays\nfiles=(\"file1.txt\" \"file2.txt\" \"file3.txt\")\ndeclare -a files=(\"file1.txt\" \"file2.txt\")\n\n# Associative arrays (bash 4+)\ndeclare -A config\nconfig[host]=\"localhost\"\nconfig[port]=\"8080\"\n\n# Integer variables\ndeclare -i count=0\ncount+=1 # Arithmetic operation\n\n# Export for environment\nexport DATABASE_URL=\"postgres://localhost/db\"\ndeclare -x DATABASE_URL=\"postgres://localhost/db\"\n```\n\n### Variable Expansion\n\n```bash\n# Default values\nvalue=\"${var:-default}\" # Use default if var is unset or empty\nvalue=\"${var-default}\" # Use default only if var is unset\nvalue=\"${var:=default}\" # Assign default if var is unset or empty\nvalue=\"${var+alternative}\" # Use alternative if var is set\n\n# String length\nlength=\"${#string}\"\n\n# Substring\nsubstring=\"${string:0:5}\" # First 5 characters\nsubstring=\"${string:5}\" # From 5th character to end\n\n# Pattern matching (prefix removal)\nfilename=\"/path/to/file.txt\"\nbasename=\"${filename##*/}\" # file.txt (remove longest match of */)\ndirname=\"${filename%/*}\" # /path/to (remove shortest match of /*)\n\n# Pattern matching (suffix removal)\nfile=\"document.tar.gz\"\nname=\"${file%.gz}\" # document.tar (remove shortest .gz)\nname=\"${file%%.*}\" # document (remove longest .*)\n\n# Search and replace\nstring=\"hello world\"\nnew_string=\"${string/world/universe}\" # First occurrence\nnew_string=\"${string//o/0}\" # All occurrences\nnew_string=\"${string/#hello/hi}\" # Prefix match\nnew_string=\"${string/%world/earth}\" # Suffix match\n\n# Case modification (bash 4+)\nupper=\"${string^^}\" # TO UPPERCASE\nlower=\"${string,,}\" # to lowercase\ncapitalize=\"${string^}\" # Capitalize first letter\n```\n\n### Command Substitution\n\n```bash\n# Modern syntax: $()\nresult=$(command) # ✓ CORRECT (preferred)\nresult=`command` # ✓ CORRECT (old style, avoid)\n\n# Nested command substitution\nouter=$(echo \"$(echo inner)\") # ✓ CORRECT (easy to nest)\nouter=`echo \\`echo inner\\`` # ✗ WRONG (hard to nest, requires escaping)\n\n# Process substitution\ndiff \u003c(command1) \u003c(command2) # Compare outputs\nwhile read -r line; do\n echo \"$line\"\ndone \u003c \u003c(command) # Read command output\n```\n\n---\n\n## Error Handling\n\n### Exit Codes\n\n```bash\n# Standard exit codes\nreadonly EXIT_SUCCESS=0\nreadonly EXIT_ERROR=1\nreadonly EXIT_INVALID_ARGS=2\nreadonly EXIT_MISSING_DEPENDENCY=3\n\n# Use meaningful exit codes\nvalidate_args() {\n if [[ $# -lt 1 ]]; then\n echo \"Error: Missing required argument\" >&2\n exit \"$EXIT_INVALID_ARGS\"\n fi\n}\n\n# Check command success\nif ! command_that_might_fail; then\n echo \"Error: Command failed\" >&2\n exit \"$EXIT_ERROR\"\nfi\n\n# Alternative syntax\ncommand_that_might_fail || {\n echo \"Error: Command failed\" >&2\n exit \"$EXIT_ERROR\"\n}\n```\n\n### Error Messages\n\n```bash\n# ALWAYS write errors to stderr\necho \"Error: Something went wrong\" >&2\n\n# Use consistent error message format\nerror() {\n local message=\"$1\"\n local code=\"${2:-$EXIT_ERROR}\"\n\n echo \"ERROR: $message\" >&2\n return \"$code\"\n}\n\n# Usage\nif ! validate_input \"$input\"; then\n error \"Invalid input: $input\" \"$EXIT_INVALID_ARGS\"\nfi\n```\n\n### Trap Handlers\n\n```bash\n# Cleanup on exit\ncleanup() {\n local exit_code=$?\n\n # Cleanup operations\n [[ -n \"${TEMP_DIR:-}\" ]] && rm -rf \"$TEMP_DIR\"\n [[ -n \"${LOCKFILE:-}\" ]] && rm -f \"$LOCKFILE\"\n\n # Don't mask errors\n exit \"$exit_code\"\n}\n\ntrap cleanup EXIT\n\n# Handle specific signals\nhandle_sigterm() {\n echo \"Received SIGTERM, shutting down...\" >&2\n # Graceful shutdown logic\n exit 143 # 128 + 15 (SIGTERM)\n}\n\ntrap handle_sigterm TERM\n\n# ERR trap (bash 4.1+)\nerror_handler() {\n local line=\"$1\"\n echo \"Error on line $line\" >&2\n}\n\ntrap 'error_handler ${LINENO}' ERR\n```\n\n### Defensive Programming\n\n```bash\n# Validate all inputs\nprocess_file() {\n local file=\"$1\"\n\n # Check file exists\n if [[ ! -f \"$file\" ]]; then\n echo \"Error: File not found: $file\" >&2\n return 1\n fi\n\n # Check file is readable\n if [[ ! -r \"$file\" ]]; then\n echo \"Error: File not readable: $file\" >&2\n return 1\n fi\n\n # Process file\n}\n\n# Check dependencies before use\ncheck_dependencies() {\n local deps=(curl jq awk sed)\n local missing=()\n\n for dep in \"${deps[@]}\"; do\n if ! command -v \"$dep\" &> /dev/null; then\n missing+=(\"$dep\")\n fi\n done\n\n if [[ ${#missing[@]} -gt 0 ]]; then\n echo \"Error: Missing dependencies: ${missing[*]}\" >&2\n exit \"$EXIT_MISSING_DEPENDENCY\"\n fi\n}\n\n# Validate environment\nif [[ -z \"${REQUIRED_VAR:-}\" ]]; then\n echo \"Error: REQUIRED_VAR must be set\" >&2\n exit 1\nfi\n```\n\n---\n\n## Input/Output\n\n### Reading User Input\n\n```bash\n# Simple read\nread -rp \"Enter your name: \" name\necho \"Hello, $name\"\n\n# Read with timeout\nif read -rt 10 -p \"Enter value (10s timeout): \" value; then\n echo \"You entered: $value\"\nelse\n echo \"Timeout or error\"\nfi\n\n# Read password (no echo)\nread -rsp \"Enter password: \" password\necho # New line after password input\n\n# Read confirmation\nconfirm() {\n local prompt=\"${1:-Are you sure?}\"\n local response\n\n read -rp \"$prompt [y/N] \" response\n case \"$response\" in\n [yY][eE][sS]|[yY])\n return 0\n ;;\n *)\n return 1\n ;;\n esac\n}\n\n# Usage\nif confirm \"Delete all files?\"; then\n rm -rf *\nfi\n```\n\n### Reading Files\n\n```bash\n# Read file line by line\nwhile IFS= read -r line; do\n echo \"Line: $line\"\ndone \u003c file.txt\n\n# Skip empty lines and comments\nwhile IFS= read -r line || [[ -n \"$line\" ]]; do\n # Skip empty lines\n [[ -z \"$line\" ]] && continue\n\n # Skip comments\n [[ \"$line\" =~ ^[[:space:]]*# ]] && continue\n\n echo \"Processing: $line\"\ndone \u003c file.txt\n\n# Read into array\nmapfile -t lines \u003c file.txt\n# Or\nreadarray -t lines \u003c file.txt\n\n# Read with null delimiter (for filenames with spaces)\nwhile IFS= read -r -d '' file; do\n echo \"File: $file\"\ndone \u003c \u003c(find . -type f -print0)\n```\n\n### Writing Output\n\n```bash\n# Stdout vs stderr\necho \"Normal output\" # stdout\necho \"Error message\" >&2 # stderr\n\n# Redirect output\ncommand > output.txt # Overwrite\ncommand >> output.txt # Append\ncommand 2> errors.txt # Stderr only\ncommand &> all_output.txt # Both stdout and stderr\ncommand > output.txt 2>&1 # Both (POSIX way)\n\n# Here documents\ncat \u003c\u003cEOF > file.txt\nLine 1\nLine 2\nVariables are expanded: $VAR\nEOF\n\n# Here documents (no expansion)\ncat \u003c\u003c'EOF' > file.txt\nLine 1\nLine 2\nVariables are NOT expanded: $VAR\nEOF\n\n# Here strings\ngrep \"pattern\" \u003c\u003c\u003c \"$variable\"\n```\n\n---\n\n## Security\n\n### Input Validation\n\n```bash\n# Validate input format\nvalidate_email() {\n local email=\"$1\"\n local regex=\"^[a-zA-Z0-9._%+-]+@[a-zA-Z0-9.-]+\\.[a-zA-Z]{2,}$\"\n\n if [[ \"$email\" =~ $regex ]]; then\n return 0\n else\n return 1\n fi\n}\n\n# Sanitize file paths\nsanitize_path() {\n local path=\"$1\"\n\n # Remove directory traversal attempts\n path=\"${path//..\\/}\"\n\n # Remove leading slashes (if restricting to relative paths)\n path=\"${path#/}\"\n\n echo \"$path\"\n}\n\n# Whitelist validation (preferred over blacklist)\nvalidate_action() {\n local action=\"$1\"\n local valid_actions=(\"start\" \"stop\" \"restart\" \"status\")\n\n for valid in \"${valid_actions[@]}\"; do\n if [[ \"$action\" == \"$valid\" ]]; then\n return 0\n fi\n done\n\n return 1\n}\n```\n\n### Command Injection Prevention\n\n```bash\n# NEVER use eval with user input\n# ✗ DANGEROUS\neval \"$user_input\"\n\n# NEVER concatenate user input into commands\n# ✗ DANGEROUS\ngrep \"$user_pattern\" file.txt # If pattern contains flags, command injection!\n\n# ✓ SAFE - Use -- to separate options from arguments\ngrep -- \"$user_pattern\" file.txt\n\n# ✓ SAFE - Use arrays for complex commands\ncommand_args=(\n --option1 \"$user_value1\"\n --option2 \"$user_value2\"\n)\ncommand \"${command_args[@]}\"\n\n# ✓ SAFE - Use printf %q for shell escaping\nsafe_value=$(printf %q \"$user_input\")\neval \"command $safe_value\" # Now safe, but avoid if possible\n```\n\n### Temporary Files\n\n```bash\n# Use mktemp for secure temporary files\nTEMP_FILE=$(mktemp) || {\n echo \"Error: Cannot create temp file\" >&2\n exit 1\n}\n\n# Cleanup on exit\ntrap 'rm -f \"$TEMP_FILE\"' EXIT\n\n# Secure temp file (mode 600)\nSECURE_TEMP=$(mktemp)\nchmod 600 \"$SECURE_TEMP\"\n\n# Temporary directory\nTEMP_DIR=$(mktemp -d) || {\n echo \"Error: Cannot create temp directory\" >&2\n exit 1\n}\n\ntrap 'rm -rf \"$TEMP_DIR\"' EXIT\n```\n\n### Secrets Management\n\n```bash\n# Don't hardcode secrets\n# ✗ WRONG\nPASSWORD=\"secret123\"\n\n# ✓ CORRECT - Read from environment\nPASSWORD=\"${DATABASE_PASSWORD:-}\"\nif [[ -z \"$PASSWORD\" ]]; then\n echo \"Error: DATABASE_PASSWORD must be set\" >&2\n exit 1\nfi\n\n# ✓ CORRECT - Read from file\nif [[ -f \"$HOME/.config/app/password\" ]]; then\n PASSWORD=$(cat \"$HOME/.config/app/password\")\nfi\n\n# ✓ CORRECT - Prompt user\nread -rsp \"Enter password: \" PASSWORD\necho\n\n# Don't log secrets\n# ✗ WRONG\necho \"Connecting with password: $PASSWORD\"\n\n# ✓ CORRECT\necho \"Connecting to database...\"\n\n# Mask secrets in process list\n# ✗ WRONG - Password visible in ps\nmysql -pSecret123\n\n# ✓ CORRECT - Use config file or environment variable\nexport MYSQL_PWD=\"$PASSWORD\"\nmysql\n\n# Clear secrets from environment when done\nunset PASSWORD\n```\n\n---\n\n## Performance\n\n### Avoid Unnecessary Subshells\n\n```bash\n# ✗ SLOW - Creates subshell\nvalue=$(expr $a + $b)\n\n# ✓ FAST - Bash arithmetic\nvalue=$((a + b))\n\n# ✗ SLOW - External command\nvalue=$(echo \"$string\" | wc -c)\n\n# ✓ FAST - Parameter expansion\nvalue=${#string}\n```\n\n### Use Bash Built-ins\n\n```bash\n# ✗ SLOW - External commands\nbasename=$(basename \"$path\")\ndirname=$(dirname \"$path\")\n\n# ✓ FAST - Parameter expansion\nbasename=\"${path##*/}\"\ndirname=\"${path%/*}\"\n\n# ✗ SLOW - grep\nif echo \"$string\" | grep -q \"pattern\"; then\n\n# ✓ FAST - Bash regex\nif [[ \"$string\" =~ pattern ]]; then\n\n# ✗ SLOW - awk/cut\nfield=$(echo \"$line\" | awk '{print $3}')\n\n# ✓ FAST - Read into array\nread -ra fields \u003c\u003c\u003c \"$line\"\nfield=\"${fields[2]}\"\n```\n\n### Efficient Loops\n\n```bash\n# ✗ SLOW - Running external command in loop\nfor i in {1..1000}; do\n result=$(date +%s)\ndone\n\n# ✓ FAST - Call once\ntimestamp=$(date +%s)\nfor i in {1..1000}; do\n result=$timestamp\ndone\n\n# ✗ SLOW - Multiple passes\ncat file | grep pattern | sort | uniq\n\n# ✓ FAST - Single pass where possible\ngrep pattern file | sort -u\n```\n\n---\n\n## Documentation\n\n### Script Header\n\n```bash\n#!/usr/bin/env bash\n#\n# backup.sh - Automated backup script\n#\n# Description:\n# Creates incremental backups of specified directories\n# to a remote server using rsync.\n#\n# Usage:\n# backup.sh [OPTIONS] \u003csource> \u003cdestination>\n#\n# Options:\n# -h, --help Show this help message\n# -v, --verbose Enable verbose output\n# -n, --dry-run Show what would be done\n# -c, --config FILE Use alternative config file\n#\n# Arguments:\n# source Directory to backup\n# destination Remote destination (user@host:/path)\n#\n# Examples:\n# backup.sh /home/user user@backup:/backups/\n# backup.sh -v -c custom.conf /data remote:/store/\n#\n# Dependencies:\n# - rsync >= 3.0\n# - ssh\n#\n# Environment Variables:\n# BACKUP_CONFIG Path to configuration file\n# BACKUP_VERBOSE Enable verbose mode if set\n#\n# Exit Codes:\n# 0 Success\n# 1 General error\n# 2 Invalid arguments\n# 3 Missing dependency\n# 4 Backup failed\n#\n# Author: Your Name \[email protected]>\n# Version: 1.2.0\n# Date: 2024-01-01\n# License: MIT\n#\n```\n\n### Inline Documentation\n\n```bash\n# Document complex logic\n# This algorithm uses binary search to find the optimal value\n# Time complexity: O(log n)\n# Space complexity: O(1)\n\n# Explain workarounds\n# HACK: Sleep needed because API has rate limiting without proper headers\nsleep 1\n\n# Document assumptions\n# Assumes file is in CSV format with header row\n\n# Link to external resources\n# See: https://docs.example.com/api for API documentation\n```\n\n### README and CHANGELOG\n\nEvery non-trivial script should have:\n\n1. **README.md** - Installation, usage, examples\n2. **CHANGELOG.md** - Version history\n3. **LICENSE** - Licensing information\n\n---\n\n## Testing\n\n### Unit Tests with BATS\n\n```bash\n# test/backup.bats\n#!/usr/bin/env bats\n\n# Setup runs before each test\nsetup() {\n # Create temp directory for tests\n TEST_DIR=\"$(mktemp -d)\"\n export TEST_DIR\n}\n\n# Teardown runs after each test\nteardown() {\n rm -rf \"$TEST_DIR\"\n}\n\n@test \"backup creates archive\" {\n run ./backup.sh \"$TEST_DIR\" backup.tar.gz\n [ \"$status\" -eq 0 ]\n [ -f backup.tar.gz ]\n}\n\n@test \"backup fails with invalid source\" {\n run ./backup.sh /nonexistent backup.tar.gz\n [ \"$status\" -eq 1 ]\n [ \"${lines[0]}\" = \"Error: Source directory not found\" ]\n}\n\n@test \"backup validates dependencies\" {\n # Mock missing dependency\n function tar() { return 127; }\n export -f tar\n\n run ./backup.sh \"$TEST_DIR\" backup.tar.gz\n [ \"$status\" -eq 3 ]\n}\n```\n\n### Integration Tests\n\n```bash\n# integration_test.sh\n#!/usr/bin/env bash\nset -euo pipefail\n\n# Test end-to-end workflow\ntest_full_workflow() {\n echo \"Testing full workflow...\"\n\n # Setup\n local test_dir=\"/tmp/test_$\"\n mkdir -p \"$test_dir\"\n\n # Execute\n ./script.sh create \"$test_dir/output\"\n ./script.sh process \"$test_dir/output\"\n ./script.sh verify \"$test_dir/output\"\n\n # Verify\n if [[ -f \"$test_dir/output/result.txt\" ]]; then\n echo \"✓ Full workflow test passed\"\n rm -rf \"$test_dir\"\n return 0\n else\n echo \"✗ Full workflow test failed\"\n rm -rf \"$test_dir\"\n return 1\n fi\n}\n\n# Run all tests\nmain() {\n local failed=0\n\n test_full_workflow || ((failed++))\n\n if [[ $failed -eq 0 ]]; then\n echo \"All tests passed\"\n exit 0\n else\n echo \"$failed test(s) failed\"\n exit 1\n fi\n}\n\nmain\n```\n\n---\n\n## Maintenance\n\n### Version Control\n\n```bash\n# Include version in script\nreadonly VERSION=\"1.2.0\"\n\nshow_version() {\n echo \"$SCRIPT_NAME version $VERSION\"\n}\n\n# Semantic versioning: MAJOR.MINOR.PATCH\n# - MAJOR: Breaking changes\n# - MINOR: New features (backward compatible)\n# - PATCH: Bug fixes\n```\n\n### Deprecation\n\n```bash\n# Deprecation warning\ndeprecated_function() {\n echo \"Warning: deprecated_function is deprecated, use new_function instead\" >&2\n new_function \"$@\"\n}\n\n# Version-based deprecation\nif [[ \"${SCRIPT_VERSION%%.*}\" -ge 2 ]]; then\n # Remove deprecated feature in version 2.0\n unset deprecated_function\nfi\n```\n\n### Backward Compatibility\n\n```bash\n# Support old parameter names\nif [[ -n \"${OLD_PARAM:-}\" && -z \"${NEW_PARAM:-}\" ]]; then\n echo \"Warning: OLD_PARAM is deprecated, use NEW_PARAM\" >&2\n NEW_PARAM=\"$OLD_PARAM\"\nfi\n\n# Support multiple config file locations\nfor config in \"$XDG_CONFIG_HOME/app/config\" \"$HOME/.config/app/config\" \"$HOME/.apprc\"; do\n if [[ -f \"$config\" ]]; then\n CONFIG_FILE=\"$config\"\n break\n fi\ndone\n```\n\n---\n\n## Summary Checklist\n\nBefore considering a bash script production-ready:\n\n- [ ] Passes ShellCheck with no warnings\n- [ ] Uses `set -euo pipefail`\n- [ ] All variables quoted properly\n- [ ] Functions use local variables\n- [ ] Has usage/help message\n- [ ] Validates all inputs\n- [ ] Checks dependencies\n- [ ] Proper error messages (to stderr)\n- [ ] Uses meaningful exit codes\n- [ ] Includes cleanup trap\n- [ ] Has inline documentation\n- [ ] Follows consistent style\n- [ ] Has unit tests (BATS)\n- [ ] Has integration tests\n- [ ] Tested on target platforms\n- [ ] Has README documentation\n- [ ] Version controlled (git)\n- [ ] Reviewed by peer\n\n**Additional for production:**\n- [ ] Has CI/CD pipeline\n- [ ] Logging implemented\n- [ ] Monitoring/alerting configured\n- [ ] Security reviewed\n- [ ] Performance tested\n- [ ] Disaster recovery plan\n- [ ] Runbook/operational docs\n\nThis ensures professional, maintainable, and robust bash scripts.\n","content_type":"text/markdown; charset=utf-8","language":"markdown","size":29804,"content_sha256":"761361d3d9db2f54c51d8cbdd77c4de40cafbe4df4c4f2c14246337a4a1c7814"},{"filename":"references/in-depth-patterns.md","content":"# Bash in-depth patterns reference\n\nDetailed patterns extracted from `SKILL.md` to keep the core skill at a navigable size. Covers function design, security, performance, testing, debugging, and advanced patterns. Pair with `best_practices.md`, `patterns_antipatterns.md`, and `platform_specifics.md` for full breadth.\n\n## Function Design\n\n```bash\n# Good function structure\nfunction_name() {\n # 1. Local variables first\n local arg1=\"$1\"\n local arg2=\"${2:-default_value}\"\n local result=\"\"\n\n # 2. Input validation\n if [[ -z \"$arg1\" ]]; then\n echo \"Error: arg1 is required\" >&2\n return 1\n fi\n\n # 3. Main logic\n result=$(some_operation \"$arg1\" \"$arg2\")\n\n # 4. Output/return\n echo \"$result\"\n return 0\n}\n\n# Use functions, not scripts-in-scripts\n# Benefits: testability, reusability, namespacing\n```\n\n## Variable Naming\n\n```bash\n# Constants: UPPER_CASE\nreadonly MAX_RETRIES=3\nreadonly CONFIG_FILE=\"/etc/app/config.conf\"\n\n# Global variables: UPPER_CASE or lower_case (be consistent)\nGLOBAL_STATE=\"initialized\"\n\n# Local variables: lower_case\nlocal user_name=\"john\"\nlocal file_count=0\n\n# Environment variables: UPPER_CASE (by convention)\nexport DATABASE_URL=\"postgres://...\"\n\n# Readonly when possible\nreadonly SCRIPT_DIR=\"$(cd \"$(dirname \"${BASH_SOURCE[0]}\")\" && pwd)\"\n```\n\n## Error Handling\n\n```bash\n# Method 1: Check exit codes explicitly\nif ! command_that_might_fail; then\n echo \"Error: Command failed\" >&2\n return 1\nfi\n\n# Method 2: Use || for alternative actions\ncommand_that_might_fail || {\n echo \"Error: Command failed\" >&2\n return 1\n}\n\n# Method 3: Trap for cleanup\ncleanup() {\n local exit_code=$?\n rm -f \"$TEMP_FILE\"\n exit \"$exit_code\"\n}\ntrap cleanup EXIT\n\n# Method 4: Custom error handler\nerror_exit() {\n local message=\"$1\"\n local code=\"${2:-1}\"\n echo \"Error: $message\" >&2\n exit \"$code\"\n}\n\n# Usage\n[[ -f \"$config_file\" ]] || error_exit \"Config file not found: $config_file\"\n```\n\n## Input Validation\n\n```bash\nvalidate_input() {\n local input=\"$1\"\n\n if [[ -z \"$input\" ]]; then\n echo \"Error: Input cannot be empty\" >&2\n return 1\n fi\n\n if [[ ! \"$input\" =~ ^[a-zA-Z0-9_-]+$ ]]; then\n echo \"Error: Input contains invalid characters\" >&2\n return 1\n fi\n\n if [[ ${#input} -gt 255 ]]; then\n echo \"Error: Input too long (max 255 characters)\" >&2\n return 1\n fi\n\n return 0\n}\n\nread -r user_input\nif validate_input \"$user_input\"; then\n process \"$user_input\"\nfi\n```\n\n## Argument Parsing\n\n```bash\nusage() {\n cat \u003c\u003cEOF\nUsage: $SCRIPT_NAME [OPTIONS] \u003ccommand>\n\nOptions:\n -h, --help Show this help\n -v, --verbose Verbose output\n -f, --file FILE Input file\n -o, --output DIR Output directory\n\nCommands:\n build Build the project\n test Run tests\nEOF\n}\n\nmain() {\n local verbose=false\n local input_file=\"\"\n local output_dir=\".\"\n local command=\"\"\n\n while [[ $# -gt 0 ]]; do\n case \"$1\" in\n -h|--help) usage; exit 0 ;;\n -v|--verbose) verbose=true; shift ;;\n -f|--file) input_file=\"$2\"; shift 2 ;;\n -o|--output) output_dir=\"$2\"; shift 2 ;;\n -*)\n echo \"Error: Unknown option: $1\" >&2\n usage >&2; exit 1 ;;\n *) command=\"$1\"; shift; break ;;\n esac\n done\n\n if [[ -z \"$command\" ]]; then\n echo \"Error: Command is required\" >&2\n usage >&2; exit 1\n fi\n\n case \"$command\" in\n build) do_build ;;\n test) do_test ;;\n *)\n echo \"Error: Unknown command: $command\" >&2\n usage >&2; exit 1 ;;\n esac\n}\n\nmain \"$@\"\n```\n\n## Logging\n\n```bash\nreadonly LOG_LEVEL_DEBUG=0\nreadonly LOG_LEVEL_INFO=1\nreadonly LOG_LEVEL_WARN=2\nreadonly LOG_LEVEL_ERROR=3\n\nLOG_LEVEL=${LOG_LEVEL:-$LOG_LEVEL_INFO}\n\nlog_debug() { [[ $LOG_LEVEL -le $LOG_LEVEL_DEBUG ]] && echo \"[DEBUG] $*\" >&2; }\nlog_info() { [[ $LOG_LEVEL -le $LOG_LEVEL_INFO ]] && echo \"[INFO] $*\" >&2; }\nlog_warn() { [[ $LOG_LEVEL -le $LOG_LEVEL_WARN ]] && echo \"[WARN] $*\" >&2; }\nlog_error() { [[ $LOG_LEVEL -le $LOG_LEVEL_ERROR ]] && echo \"[ERROR] $*\" >&2; }\n\nlog_with_timestamp() {\n local level=\"$1\"\n shift\n echo \"[$(date +'%Y-%m-%d %H:%M:%S')] [$level] $*\" >&2\n}\n\nlog_info \"Starting process\"\nlog_error \"Failed to connect to database\"\n```\n\n## Security\n\n### Command Injection Prevention\n\n```bash\n# NEVER use eval with user input - DANGEROUS\neval \"$user_input\" # WRONG\neval \"var_$user_input=value\" # WRONG\n\n# NEVER concatenate user input into commands\ngrep \"$user_pattern\" file.txt # If pattern contains -e flag, injection possible\n\n# Use arrays\ngrep_args=(\"$user_pattern\" \"file.txt\")\ngrep \"${grep_args[@]}\"\n\n# Use -- to separate options from arguments\ngrep -- \"$user_pattern\" file.txt\n```\n\n### Path Traversal Prevention\n\n```bash\nsanitize_path() {\n local path=\"$1\"\n path=\"${path//..\\/}\"\n path=\"${path//\\/..\\//}\"\n path=\"${path#/}\"\n echo \"$path\"\n}\n\nis_safe_path() {\n local file_path=\"$1\"\n local base_dir=\"$2\"\n\n local real_path\n real_path=$(readlink -f \"$file_path\" 2>/dev/null) || return 1\n local real_base\n real_base=$(readlink -f \"$base_dir\" 2>/dev/null) || return 1\n\n [[ \"$real_path\" == \"$real_base\"/* ]]\n}\n\nif is_safe_path \"$user_file\" \"/var/app/data\"; then\n process_file \"$user_file\"\nelse\n echo \"Error: Invalid file path\" >&2\n exit 1\nfi\n```\n\n### Privilege Management\n\n```bash\n# Refuse to run as root\nif [[ $EUID -eq 0 ]]; then\n echo \"Error: Do not run this script as root\" >&2\n exit 1\nfi\n\ndrop_privileges() {\n local user=\"$1\"\n if [[ $EUID -eq 0 ]]; then\n exec sudo -u \"$user\" \"$0\" \"$@\"\n fi\n}\n\nrun_as_root() {\n if [[ $EUID -ne 0 ]]; then\n sudo \"$@\"\n else\n \"$@\"\n fi\n}\n```\n\n### Temporary File Handling\n\n```bash\nreadonly TEMP_DIR=$(mktemp -d)\nreadonly TEMP_FILE=$(mktemp)\n\ncleanup() {\n rm -rf \"$TEMP_DIR\"\n rm -f \"$TEMP_FILE\"\n}\ntrap cleanup EXIT\n\n# Secure temporary file (owner-only)\nsecure_temp=$(mktemp)\nchmod 600 \"$secure_temp\"\n```\n\n## Performance Optimization\n\n### Avoid Unnecessary Subshells\n\n```bash\n# SLOW - subshell per iteration\nwhile IFS= read -r line; do\n count=$(echo \"$count + 1\" | bc)\ndone \u003c file.txt\n\n# FAST - bash arithmetic\ncount=0\nwhile IFS= read -r line; do\n ((count++))\ndone \u003c file.txt\n```\n\n### Use Bash Built-ins\n\n```bash\n# Slow: external commands\nlength=$(echo \"$string\" | wc -c)\nupper=$(echo \"$string\" | tr '[:lower:]' '[:upper:]')\n\n# Fast: bash built-ins\nlength=${#string}\nupper=${string^^}\n\n# String contains check\nif [[ \"$haystack\" == *\"$needle\"* ]]; then\n echo \"Found\"\nfi\n```\n\n### Process Substitution vs Pipes\n\n```bash\n# Pipes start a subshell - variables don't persist\ncount=0\necho \"data\" | while read -r line; do\n ((count++)) # changes lost in subshell\ndone\n\n# Process substitution keeps the current shell\ncount=0\nwhile read -r line; do\n ((count++))\ndone \u003c \u003c(echo \"data\")\n```\n\n### Array Operations\n\n```bash\narr=(\"one\" \"two\" \"three\")\n\nlength=${#arr[@]}\nlast_index=$((${#arr[@]} - 1))\n\narr+=(\"four\")\nunset 'arr[1]' # remove by index\narr=(\"${arr[@]}\") # reindex after unset\n\n# Iterate\nfor item in \"${arr[@]}\"; do\n echo \"$item\"\ndone\n\n# Iterate with index\nfor i in \"${!arr[@]}\"; do\n echo \"$i: ${arr[$i]}\"\ndone\n```\n\n## Testing\n\n### Unit Testing with BATS\n\n```bash\n# test/script.bats\n#!/usr/bin/env bats\n\nload '../script.sh'\n\n@test \"function returns correct value\" {\n result=$(my_function \"input\")\n [ \"$result\" = \"expected\" ]\n}\n\n@test \"function handles empty input\" {\n run my_function \"\"\n [ \"$status\" -eq 1 ]\n [ \"${lines[0]}\" = \"Error: Input cannot be empty\" ]\n}\n\n@test \"function validates input format\" {\n run my_function \"invalid@input\"\n [ \"$status\" -eq 1 ]\n}\n\n# Run: bats test/script.bats\n```\n\n### Integration Testing\n\n```bash\n# integration_test.sh\n#!/usr/bin/env bash\nset -euo pipefail\n\nsetup() {\n export TEST_DIR=$(mktemp -d)\n export TEST_FILE=\"$TEST_DIR/test.txt\"\n}\n\nteardown() {\n rm -rf \"$TEST_DIR\"\n}\n\ntest_file_creation() {\n ./script.sh create \"$TEST_FILE\"\n if [[ ! -f \"$TEST_FILE\" ]]; then\n echo \"FAIL: File was not created\"\n return 1\n fi\n echo \"PASS: File creation works\"\n}\n\nmain() {\n setup\n trap teardown EXIT\n test_file_creation || exit 1\n echo \"All tests passed\"\n}\n\nmain\n```\n\n### CI/CD Integration\n\n```yaml\n# .github/workflows/test.yml\nname: Test\n\non: [push, pull_request]\n\njobs:\n test:\n runs-on: ubuntu-latest\n steps:\n - uses: actions/checkout@v3\n\n - name: Install shellcheck\n run: sudo apt-get install -y shellcheck\n\n - name: Run shellcheck\n run: find . -name \"*.sh\" -exec shellcheck {} +\n\n - name: Install bats\n run: |\n git clone https://github.com/bats-core/bats-core.git\n cd bats-core\n sudo ./install.sh /usr/local\n\n - name: Run tests\n run: bats test/\n```\n\n## Debugging Techniques\n\n### Debug Mode\n\n```bash\n# Method 1: set -x\nset -x\ncommand1\ncommand2\nset +x\n\n# Method 2: PS4 for richer trace output\nexport PS4='+(${BASH_SOURCE}:${LINENO}): ${FUNCNAME[0]:+${FUNCNAME[0]}(): }'\nset -x\n\n# Method 3: Conditional debugging\nDEBUG=${DEBUG:-false}\ndebug() {\n if [[ \"$DEBUG\" == \"true\" ]]; then\n echo \"[DEBUG] $*\" >&2\n fi\n}\n# Usage: DEBUG=true ./script.sh\n```\n\n### Tracing and Profiling\n\n```bash\ntrace() {\n echo \"[TRACE] Function: ${FUNCNAME[1]}, Args: $*\" >&2\n}\n\nmy_function() {\n trace \"$@\"\n # Function logic\n}\n\nprofile() {\n local start=$(date +%s%N)\n \"$@\"\n local end=$(date +%s%N)\n local duration=$(( (end - start) / 1000000 ))\n echo \"[PROFILE] Command '$*' took ${duration}ms\" >&2\n}\n\n# Usage\nprofile slow_command arg1 arg2\n```\n\n### Common Issues and Solutions\n\n```bash\n# Script works in bash but not in sh - check bashisms\ncheckbashisms script.sh\n\n# Works locally but not on server - check PATH/env\nenv\necho \"$PATH\"\n\n# Whitespace in filenames breaking script - always quote\nfor file in *.txt; do\n process \"$file\" # not: process $file\ndone\n\n# Different behavior in cron - set PATH explicitly\nPATH=/usr/local/bin:/usr/bin:/bin\nexport PATH\n```\n\n## Advanced Patterns\n\n### Configuration File Parsing\n\n```bash\n# Simple sourcing (dangerous if file not trusted)\nload_config() {\n local config_file=\"$1\"\n if [[ ! -f \"$config_file\" ]]; then\n echo \"Error: Config file not found: $config_file\" >&2\n return 1\n fi\n # shellcheck source=/dev/null\n source \"$config_file\"\n}\n\n# Safe parsing - no code execution\nread_config() {\n local config_file=\"$1\"\n while IFS='=' read -r key value; do\n [[ \"$key\" =~ ^[[:space:]]*# ]] && continue\n [[ -z \"$key\" ]] && continue\n key=$(echo \"$key\" | tr -d ' ')\n value=$(echo \"$value\" | sed 's/^[[:space:]]*//;s/[[:space:]]*$//')\n declare -g \"$key=$value\"\n done \u003c \"$config_file\"\n}\n```\n\n### Parallel Processing\n\n```bash\nprocess_files_parallel() {\n local max_jobs=4\n local job_count=0\n\n for file in *.txt; do\n process_file \"$file\" &\n ((job_count++))\n if [[ $job_count -ge $max_jobs ]]; then\n wait -n\n ((job_count--))\n fi\n done\n\n wait\n}\n\n# Using GNU Parallel\nparallel_with_gnu() {\n parallel -j 4 process_file ::: *.txt\n}\n```\n\n### Signal Handling\n\n```bash\nshutdown_requested=false\n\nhandle_sigterm() {\n echo \"Received SIGTERM, shutting down gracefully...\" >&2\n shutdown_requested=true\n}\n\ntrap handle_sigterm SIGTERM SIGINT\n\nmain_loop() {\n while [[ \"$shutdown_requested\" == \"false\" ]]; do\n sleep 1\n done\n echo \"Shutdown complete\" >&2\n}\n\nmain_loop\n```\n\n### Retries with Exponential Backoff\n\n```bash\nretry_with_backoff() {\n local max_attempts=5\n local timeout=1\n local attempt=1\n local exitCode=0\n\n while [[ $attempt -le $max_attempts ]]; do\n if \"$@\"; then\n return 0\n else\n exitCode=$?\n fi\n echo \"Attempt $attempt failed! Retrying in $timeout seconds...\" >&2\n sleep \"$timeout\"\n attempt=$((attempt + 1))\n timeout=$((timeout * 2))\n done\n\n echo \"Command failed after $max_attempts attempts!\" >&2\n return \"$exitCode\"\n}\n\n# Usage\nretry_with_backoff curl -f https://api.example.com/health\n```\n","content_type":"text/markdown; charset=utf-8","language":"markdown","size":12305,"content_sha256":"40a226846d81fc87722205d0bdb1fb53c5cb50d71692b6142317ec0e529b1dca"},{"filename":"references/patterns_antipatterns.md","content":"# Common Bash Patterns and Anti-Patterns\n\nCollection of proven patterns and common mistakes in bash scripting with explanations and solutions.\n\n---\n\n## Table of Contents\n\n1. [Variable Handling](#variable-handling)\n2. [Command Execution](#command-execution)\n3. [File Operations](#file-operations)\n4. [String Processing](#string-processing)\n5. [Arrays and Loops](#arrays-and-loops)\n6. [Conditionals and Tests](#conditionals-and-tests)\n7. [Functions](#functions)\n8. [Error Handling](#error-handling)\n9. [Process Management](#process-management)\n10. [Security Patterns](#security-patterns)\n\n---\n\n## 🚨 CRITICAL GUIDELINES\n\n### Windows File Path Requirements\n\n**MANDATORY: Always Use Backslashes on Windows for File Paths**\n\nWhen using Edit or Write tools on Windows, you MUST use backslashes (`\\`) in file paths, NOT forward slashes (`/`).\n\n**Examples:**\n- ❌ WRONG: `D:/repos/project/file.tsx`\n- ✅ CORRECT: `D:\\repos\\project\\file.tsx`\n\nThis applies to:\n- Edit tool file_path parameter\n- Write tool file_path parameter\n- All file operations on Windows systems\n\n\n### Documentation Guidelines\n\n**NEVER create new documentation files unless explicitly requested by the user.**\n\n- **Priority**: Update existing README.md files rather than creating new documentation\n- **Repository cleanliness**: Keep repository root clean - only README.md unless user requests otherwise\n- **Style**: Documentation should be concise, direct, and professional - avoid AI-generated tone\n- **User preference**: Only create additional .md files when user specifically asks for documentation\n\n\n---\n\n## Variable Handling\n\n### Pattern: Safe Variable Expansion\n\n```bash\n# ✓ GOOD: Always quote variables\necho \"$variable\"\ncp \"$source\" \"$destination\"\nrm -rf \"$directory\"\n\n# ✗ BAD: Unquoted variables\necho $variable # Word splitting and globbing\ncp $source $destination # Breaks with spaces\nrm -rf $directory # VERY DANGEROUS unquoted\n```\n\n**Why:** Unquoted variables undergo word splitting and pathname expansion, leading to unexpected behavior.\n\n### Pattern: Default Values\n\n```bash\n# ✓ GOOD: Use parameter expansion for defaults\ntimeout=\"${TIMEOUT:-30}\"\nconfig=\"${CONFIG_FILE:-$HOME/.config/app.conf}\"\n\n# ✗ BAD: Manual check\nif [ -z \"$TIMEOUT\" ]; then\n timeout=30\nelse\n timeout=\"$TIMEOUT\"\nfi\n```\n\n**Why:** Parameter expansion is concise, readable, and handles edge cases correctly.\n\n### Anti-Pattern: Confusing Assignment and Comparison\n\n```bash\n# ✗ VERY BAD: Using = instead of ==\nif [ \"$var\" = \"value\" ]; then # Assignment in POSIX test!\n echo \"Match\"\nfi\n\n# ✓ GOOD: Use == or = correctly\nif [[ \"$var\" == \"value\" ]]; then # Comparison in bash\n echo \"Match\"\nfi\n\n# ✓ GOOD: POSIX-compliant\nif [ \"$var\" = \"value\" ]; then # Single = is correct in [ ]\n echo \"Match\"\nfi\n```\n\n**Why:** In `[[ ]]`, both `=` and `==` work. In `[ ]`, only `=` is POSIX-compliant.\n\n### Anti-Pattern: Unset Variable Access\n\n```bash\n# ✗ BAD: Accessing undefined variables\necho \"Value: $undefined_variable\" # Silent error, prints \"Value: \"\n\n# ✓ GOOD: Use set -u\nset -u\necho \"Value: $undefined_variable\" # Error: undefined_variable: unbound variable\n\n# ✓ GOOD: Provide default\necho \"Value: ${undefined_variable:-default}\"\n```\n\n**Why:** `set -u` catches typos and logic errors early.\n\n---\n\n## Command Execution\n\n### Pattern: Check Command Existence\n\n```bash\n# ✓ GOOD: Use command -v\nif command -v jq &> /dev/null; then\n echo \"jq is installed\"\nelse\n echo \"jq is not installed\" >&2\n exit 1\nfi\n\n# ✗ BAD: Using which\nif which jq; then # Deprecated, not POSIX\n echo \"jq is installed\"\nfi\n\n# ✗ BAD: Using type\nif type jq; then # Verbose output\n echo \"jq is installed\"\nfi\n```\n\n**Why:** `command -v` is POSIX-compliant, silent, and reliable.\n\n### Pattern: Command Substitution\n\n```bash\n# ✓ GOOD: Modern syntax with $()\nresult=$(command arg1 arg2)\ntimestamp=$(date +%s)\n\n# ✗ BAD: Backticks (hard to nest)\nresult=`command arg1 arg2`\ntimestamp=`date +%s`\n\n# ✓ GOOD: Nested substitution\nresult=$(echo \"Outer: $(echo \"Inner\")\")\n\n# ✗ BAD: Nested backticks (requires escaping)\nresult=`echo \"Outer: \\`echo \\\"Inner\\\"\\`\"`\n```\n\n**Why:** `$()` is easier to read, nest, and maintain.\n\n### Anti-Pattern: Useless Use of Cat\n\n```bash\n# ✗ BAD: UUOC (Useless Use of Cat)\ncat file.txt | grep \"pattern\"\n\n# ✓ GOOD: Direct input\ngrep \"pattern\" file.txt\n\n# ✗ BAD: Multiple cats\ncat file1 | grep pattern | cat | sort | cat\n\n# ✓ GOOD: Direct pipeline\ngrep pattern file1 | sort\n```\n\n**Why:** Unnecessary `cat` wastes resources and adds extra processes.\n\n### Anti-Pattern: Using ls in Scripts\n\n```bash\n# ✗ BAD: Parsing ls output\nfor file in $(ls *.txt); do\n echo \"$file\"\ndone\n\n# ✓ GOOD: Use globbing\nfor file in *.txt; do\n [[ -f \"$file\" ]] || continue # Skip if no matches\n echo \"$file\"\ndone\n\n# ✗ BAD: Counting files with ls\ncount=$(ls -1 | wc -l)\n\n# ✓ GOOD: Use array\nfiles=(*)\ncount=${#files[@]}\n```\n\n**Why:** `ls` output is meant for humans, not scripts. Parsing it breaks with spaces, newlines, etc.\n\n---\n\n## File Operations\n\n### Pattern: Safe File Reading\n\n```bash\n# ✓ GOOD: Preserve leading/trailing whitespace and backslashes\nwhile IFS= read -r line; do\n echo \"Line: $line\"\ndone \u003c file.txt\n\n# ✗ BAD: Without IFS= (strips leading/trailing whitespace)\nwhile read -r line; do\n echo \"Line: $line\"\ndone \u003c file.txt\n\n# ✗ BAD: Without -r (interprets backslashes)\nwhile IFS= read line; do\n echo \"Line: $line\"\ndone \u003c file.txt\n```\n\n**Why:** `IFS=` prevents trimming, `-r` prevents backslash interpretation.\n\n### Pattern: Null-Delimited Files\n\n```bash\n# ✓ GOOD: For filenames with special characters\nfind . -name \"*.txt\" -print0 | while IFS= read -r -d '' file; do\n echo \"Processing: $file\"\ndone\n\n# Or with mapfile (bash 4+)\nmapfile -d '' -t files \u003c \u003c(find . -name \"*.txt\" -print0)\nfor file in \"${files[@]}\"; do\n echo \"Processing: $file\"\ndone\n\n# ✗ BAD: Newline-delimited (breaks with newlines in filenames)\nfind . -name \"*.txt\" | while IFS= read -r file; do\n echo \"Processing: $file\"\ndone\n```\n\n**Why:** Filenames can contain any character except null and slash.\n\n### Anti-Pattern: Testing File Existence Incorrectly\n\n```bash\n# ✗ BAD: Using ls to test existence\nif ls file.txt &> /dev/null; then\n echo \"File exists\"\nfi\n\n# ✓ GOOD: Use test operators\nif [[ -f file.txt ]]; then\n echo \"File exists\"\nfi\n\n# ✓ GOOD: Different tests\n[[ -e path ]] # Exists (file or directory)\n[[ -f file ]] # Regular file\n[[ -d dir ]] # Directory\n[[ -L link ]] # Symbolic link\n[[ -r file ]] # Readable\n[[ -w file ]] # Writable\n[[ -x file ]] # Executable\n```\n\n**Why:** Test operators are the correct, efficient way to check file properties.\n\n### Pattern: Temporary Files\n\n```bash\n# ✓ GOOD: Secure temporary file\ntemp_file=$(mktemp)\ntrap 'rm -f \"$temp_file\"' EXIT\n\n# Use temp file\necho \"data\" > \"$temp_file\"\n\n# ✗ BAD: Insecure temp file\ntemp_file=\"/tmp/myapp.$\"\necho \"data\" > \"$temp_file\"\n# No cleanup!\n\n# ✓ GOOD: Temporary directory\ntemp_dir=$(mktemp -d)\ntrap 'rm -rf \"$temp_dir\"' EXIT\n```\n\n**Why:** `mktemp` creates secure, unique files and prevents race conditions.\n\n---\n\n## String Processing\n\n### Pattern: String Manipulation with Parameter Expansion\n\n```bash\n# ✓ GOOD: Use bash parameter expansion\nfilename=\"document.tar.gz\"\nbasename=\"${filename%%.*}\" # document\nextension=\"${filename##*.}\" # gz\nname=\"${filename%.gz}\" # document.tar\n\n# ✗ BAD: Using external commands\nbasename=$(echo \"$filename\" | sed 's/\\..*$//')\nextension=$(echo \"$filename\" | awk -F. '{print $NF}')\n```\n\n**Why:** Parameter expansion is faster and doesn't spawn processes.\n\n### Pattern: String Comparison\n\n```bash\n# ✓ GOOD: Use [[ ]] for strings\nif [[ \"$string1\" == \"$string2\" ]]; then\n echo \"Equal\"\nfi\n\n# ✓ GOOD: Pattern matching\nif [[ \"$filename\" == *.txt ]]; then\n echo \"Text file\"\nfi\n\n# ✓ GOOD: Regex matching\nif [[ \"$email\" =~ ^[a-zA-Z0-9._%+-]+@[a-zA-Z0-9.-]+\\.[a-zA-Z]{2,}$ ]]; then\n echo \"Valid email\"\nfi\n\n# ✗ BAD: Using grep for simple string check\nif echo \"$string\" | grep -q \"substring\"; then\n echo \"Found\"\nfi\n\n# ✓ GOOD: Use substring matching\nif [[ \"$string\" == *\"substring\"* ]]; then\n echo \"Found\"\nfi\n```\n\n**Why:** `[[ ]]` is bash-native, faster, and more readable.\n\n### Anti-Pattern: Word Splitting Issues\n\n```bash\n# ✗ BAD: Unquoted expansion with spaces\nvar=\"file1.txt file2.txt\"\nfor file in $var; do # Splits on spaces!\n echo \"$file\" # file1.txt, then file2.txt\ndone\n\n# ✓ GOOD: Use array\nfiles=(\"file1.txt\" \"file2.txt\")\nfor file in \"${files[@]}\"; do\n echo \"$file\"\ndone\n\n# ✗ BAD: Word splitting in command arguments\nfile=\"my file.txt\"\nrm $file # Tries to remove \"my\" and \"file.txt\"!\n\n# ✓ GOOD: Quote variables\nrm \"$file\"\n```\n\n**Why:** Word splitting on spaces is a major source of bugs.\n\n---\n\n## Arrays and Loops\n\n### Pattern: Array Declaration and Use\n\n```bash\n# ✓ GOOD: Array declaration\nfiles=(\"file1.txt\" \"file2.txt\" \"file 3.txt\")\n\n# ✓ GOOD: Array expansion (each element quoted)\nfor file in \"${files[@]}\"; do\n echo \"$file\"\ndone\n\n# ✗ BAD: Unquoted array expansion\nfor file in ${files[@]}; do # Word splitting!\n echo \"$file\"\ndone\n\n# ✓ GOOD: Add to array\nfiles+=(\"file4.txt\")\n\n# ✓ GOOD: Array length\necho \"Count: ${#files[@]}\"\n\n# ✓ GOOD: Array indices\nfor i in \"${!files[@]}\"; do\n echo \"File $i: ${files[$i]}\"\ndone\n```\n\n**Why:** Proper array handling prevents word splitting and globbing issues.\n\n### Pattern: Reading Command Output into Array\n\n```bash\n# ✓ GOOD: mapfile/readarray (bash 4+)\nmapfile -t lines \u003c file.txt\n\n# ✓ GOOD: With command substitution\nmapfile -t files \u003c \u003c(find . -name \"*.txt\")\n\n# ✗ BAD: Word splitting\nfiles=($(find . -name \"*.txt\")) # Breaks with spaces in filenames!\n\n# ✓ GOOD: Alternative (POSIX-compatible)\nwhile IFS= read -r file; do\n files+=(\"$file\")\ndone \u003c \u003c(find . -name \"*.txt\")\n```\n\n**Why:** `mapfile` is efficient and handles special characters correctly.\n\n### Anti-Pattern: C-Style For Loops for Arrays\n\n```bash\n# ✗ BAD: C-style loop for arrays\nfor ((i=0; i\u003c${#files[@]}; i++)); do\n echo \"${files[$i]}\"\ndone\n\n# ✓ GOOD: For-in loop\nfor file in \"${files[@]}\"; do\n echo \"$file\"\ndone\n\n# ✓ ACCEPTABLE: When you need the index\nfor i in \"${!files[@]}\"; do\n echo \"Index $i: ${files[$i]}\"\ndone\n```\n\n**Why:** For-in loops are simpler and less error-prone.\n\n### Pattern: Loop over Range\n\n```bash\n# ✓ GOOD: Brace expansion\nfor i in {1..10}; do\n echo \"$i\"\ndone\n\n# ✓ GOOD: With variables (bash 4+)\nstart=1\nend=10\nfor i in $(seq $start $end); do\n echo \"$i\"\ndone\n\n# ✓ GOOD: C-style (arithmetic)\nfor ((i=1; i\u003c=10; i++)); do\n echo \"$i\"\ndone\n\n# ✗ BAD: Using seq in a loop unnecessarily\nfor i in $(seq 1 1000000); do # Creates huge string in memory!\n echo \"$i\"\ndone\n\n# ✓ GOOD: Use C-style for large ranges\nfor ((i=1; i\u003c=1000000; i++)); do\n echo \"$i\"\ndone\n```\n\n**Why:** Choose the right loop construct based on the use case.\n\n---\n\n## Conditionals and Tests\n\n### Pattern: File Tests\n\n```bash\n# ✓ GOOD: Use appropriate test\nif [[ -f \"$file\" ]]; then # Regular file\nif [[ -d \"$dir\" ]]; then # Directory\nif [[ -e \"$path\" ]]; then # Exists (any type)\nif [[ -L \"$link\" ]]; then # Symbolic link\nif [[ -r \"$file\" ]]; then # Readable\nif [[ -w \"$file\" ]]; then # Writable\nif [[ -x \"$file\" ]]; then # Executable\nif [[ -s \"$file\" ]]; then # Non-empty file\n\n# ✗ BAD: Incorrect test\nif [[ -e \"$file\" ]]; then # Exists, but could be directory!\n cat \"$file\" # Fails if directory\nfi\n\n# ✓ GOOD: Specific test\nif [[ -f \"$file\" ]]; then\n cat \"$file\"\nfi\n```\n\n**Why:** Use the most specific test for your use case.\n\n### Pattern: Numeric Comparison\n\n```bash\n# ✓ GOOD: Arithmetic context\nif (( num > 10 )); then\n echo \"Greater than 10\"\nfi\n\n# ✓ GOOD: Test operator\nif [[ $num -gt 10 ]]; then\n echo \"Greater than 10\"\nfi\n\n# ✗ BAD: String comparison for numbers\nif [[ \"$num\" > \"10\" ]]; then # Lexicographic comparison!\n echo \"Greater than 10\" # \"9\" > \"10\" is true!\nfi\n```\n\n**Why:** Use numeric comparison operators for numbers.\n\n### Anti-Pattern: Testing Boolean Strings\n\n```bash\n# ✗ BAD: Comparing to string \"true\"\nif [[ \"$flag\" == \"true\" ]]; then\n do_something\nfi\n\n# ✓ GOOD: Use boolean variable directly\nflag=false # or true\n\nif $flag; then\n do_something\nfi\n\n# ✓ BETTER: Use integers for flags\nflag=0 # false\nflag=1 # true\n\nif (( flag )); then\n do_something\nfi\n\n# ✓ GOOD: For command success/failure\nif command; then\n echo \"Success\"\nfi\n```\n\n**Why:** Boolean strings are error-prone; use actual booleans or return codes.\n\n### Pattern: Multiple Conditions\n\n```bash\n# ✓ GOOD: Logical operators\nif [[ condition1 && condition2 ]]; then\n echo \"Both true\"\nfi\n\nif [[ condition1 || condition2 ]]; then\n echo \"At least one true\"\nfi\n\nif [[ ! condition ]]; then\n echo \"False\"\nfi\n\n# ✗ BAD: Separate tests\nif [ condition1 -a condition2 ]; then # Deprecated\n echo \"Both true\"\nfi\n\n# ✗ BAD: Nested ifs for AND\nif [[ condition1 ]]; then\n if [[ condition2 ]]; then\n echo \"Both true\"\n fi\nfi\n```\n\n**Why:** `&&` and `||` in `[[ ]]` are clearer and recommended.\n\n---\n\n## Functions\n\n### Pattern: Function Return Values\n\n```bash\n# ✓ GOOD: Return status, output to stdout\nget_value() {\n local value=\"result\"\n\n if [[ -n \"$value\" ]]; then\n echo \"$value\"\n return 0\n else\n return 1\n fi\n}\n\n# Usage\nif result=$(get_value); then\n echo \"Got: $result\"\nelse\n echo \"Failed\"\nfi\n\n# ✗ BAD: Using return for data\nget_value() {\n return 42 # Can only return 0-255!\n}\nresult=$? # Gets 42, but limited range\n```\n\n**Why:** `return` is for exit status (0-255), not data. Output to stdout for data.\n\n### Pattern: Local Variables in Functions\n\n```bash\n# ✓ GOOD: Declare local variables\nmy_function() {\n local arg=\"$1\"\n local result=\"\"\n\n result=$(process \"$arg\")\n echo \"$result\"\n}\n\n# ✗ BAD: Global variables\nmy_function() {\n arg=\"$1\" # Pollutes global namespace!\n result=\"\" # Global variable!\n\n result=$(process \"$arg\")\n echo \"$result\"\n}\n```\n\n**Why:** Local variables prevent unexpected side effects.\n\n### Anti-Pattern: Capturing Local Command Failure\n\n```bash\n# ✗ BAD: Local declaration masks command failure\nmy_function() {\n local result=$(command_that_fails) # $? is from 'local', not 'command'!\n echo \"$result\"\n}\n\n# ✓ GOOD: Separate declaration and assignment\nmy_function() {\n local result\n result=$(command_that_fails) || return 1\n echo \"$result\"\n}\n\n# ✓ GOOD: Check command separately\nmy_function() {\n local result\n\n if ! result=$(command_that_fails); then\n return 1\n fi\n\n echo \"$result\"\n}\n```\n\n**Why:** Combining `local` and command substitution hides command failure.\n\n---\n\n## Error Handling\n\n### Pattern: Check Command Success\n\n```bash\n# ✓ GOOD: Direct check\nif ! command; then\n echo \"Command failed\" >&2\n exit 1\nfi\n\n# ✓ GOOD: With logical operator\ncommand || {\n echo \"Command failed\" >&2\n exit 1\n}\n\n# ✓ GOOD: Capture output and check\nif ! output=$(command 2>&1); then\n echo \"Command failed: $output\" >&2\n exit 1\nfi\n\n# ✗ BAD: Not checking status\ncommand # What if it fails?\nnext_command\n```\n\n**Why:** Always check if commands succeed unless failure is acceptable.\n\n### Pattern: Error Messages to stderr\n\n```bash\n# ✓ GOOD: Errors to stderr\necho \"Error: Invalid argument\" >&2\n\n# ✗ BAD: Errors to stdout\necho \"Error: Invalid argument\"\n\n# ✓ GOOD: Error function\nerror() {\n echo \"ERROR: $*\" >&2\n}\n\nerror \"Something went wrong\"\n```\n\n**Why:** stderr is for errors, stdout is for data output.\n\n### Pattern: Cleanup on Exit\n\n```bash\n# ✓ GOOD: Trap for cleanup\ntemp_file=$(mktemp)\n\ncleanup() {\n rm -f \"$temp_file\"\n}\n\ntrap cleanup EXIT\n\n# Do work with temp_file\n\n# ✗ BAD: Manual cleanup (might not run)\ntemp_file=$(mktemp)\n\n# Do work\n\nrm -f \"$temp_file\" # Doesn't run if script exits early!\n```\n\n**Why:** Trap ensures cleanup runs on exit, even on errors.\n\n### Anti-Pattern: Silencing Errors\n\n```bash\n# ✗ BAD: Silencing errors\ncommand 2>/dev/null # What if it fails?\nnext_command\n\n# ✓ GOOD: Check status even if silencing output\nif ! command 2>/dev/null; then\n echo \"Command failed\" >&2\n exit 1\nfi\n\n# ✓ ACCEPTABLE: When failure is expected and acceptable\nif command 2>/dev/null; then\n echo \"Command succeeded\"\nelse\n echo \"Command failed (expected)\"\nfi\n```\n\n**Why:** Silencing errors without checking status leads to silent failures.\n\n---\n\n## Process Management\n\n### Pattern: Background Jobs\n\n```bash\n# ✓ GOOD: Track background jobs\nlong_running_task &\npid=$!\n\n# Wait for completion\nif wait \"$pid\"; then\n echo \"Task completed successfully\"\nelse\n echo \"Task failed\" >&2\nfi\n\n# ✓ GOOD: Multiple background jobs\njob1 &\npid1=$!\njob2 &\npid2=$!\n\nwait \"$pid1\" \"$pid2\"\n```\n\n**Why:** Proper job management prevents zombie processes.\n\n### Pattern: Timeout for Commands\n\n```bash\n# ✓ GOOD: Use timeout command (if available)\nif timeout 30 long_running_command; then\n echo \"Completed within timeout\"\nelse\n echo \"Timed out or failed\" >&2\nfi\n\n# ✓ GOOD: Manual timeout implementation\ntimeout_command() {\n local timeout=$1\n shift\n\n \"$@\" &\n local pid=$!\n\n ( sleep \"$timeout\"; kill \"$pid\" 2>/dev/null ) &\n local killer=$!\n\n if wait \"$pid\" 2>/dev/null; then\n kill \"$killer\" 2>/dev/null\n wait \"$killer\" 2>/dev/null\n return 0\n else\n return 1\n fi\n}\n\ntimeout_command 30 long_running_command\n```\n\n**Why:** Prevents scripts from hanging indefinitely.\n\n### Anti-Pattern: Killing Processes Unsafely\n\n```bash\n# ✗ BAD: kill -9 immediately\nkill -9 \"$pid\"\n\n# ✓ GOOD: Graceful shutdown first\nkill -TERM \"$pid\"\nsleep 2\n\nif kill -0 \"$pid\" 2>/dev/null; then\n echo \"Process still running, forcing...\" >&2\n kill -KILL \"$pid\"\nfi\n\n# ✓ GOOD: With timeout\ngraceful_kill() {\n local pid=$1\n local timeout=${2:-10}\n\n kill -TERM \"$pid\" 2>/dev/null || return 0\n\n for ((i=0; i\u003ctimeout; i++)); do\n if ! kill -0 \"$pid\" 2>/dev/null; then\n return 0\n fi\n sleep 1\n done\n\n echo \"Forcing kill of $pid\" >&2\n kill -KILL \"$pid\" 2>/dev/null\n}\n```\n\n**Why:** SIGTERM allows graceful shutdown; SIGKILL should be last resort.\n\n---\n\n## Security Patterns\n\n### Pattern: Input Validation\n\n```bash\n# ✓ GOOD: Whitelist validation\nvalidate_action() {\n local action=$1\n case \"$action\" in\n start|stop|restart|status)\n return 0\n ;;\n *)\n echo \"Error: Invalid action: $action\" >&2\n return 1\n ;;\n esac\n}\n\n# ✗ BAD: No validation\naction=\"$1\"\nsystemctl \"$action\" myservice # User can pass arbitrary commands!\n\n# ✓ GOOD: Validate first\nif validate_action \"$1\"; then\n systemctl \"$1\" myservice\nelse\n exit 1\nfi\n```\n\n**Why:** Whitelist validation prevents command injection.\n\n### Pattern: Avoid eval\n\n```bash\n# ✗ BAD: eval with user input\neval \"$user_command\" # DANGEROUS!\n\n# ✓ GOOD: Use arrays\ncommand_args=(\"$arg1\" \"$arg2\" \"$arg3\")\ncommand \"${command_args[@]}\"\n\n# ✗ BAD: Dynamic variable names\neval \"var_$name=value\"\n\n# ✓ GOOD: Associative arrays (bash 4+)\ndeclare -A vars\nvars[$name]=\"value\"\n```\n\n**Why:** `eval` with user input is a security vulnerability.\n\n### Pattern: Safe PATH\n\n```bash\n# ✓ GOOD: Set explicit PATH\nexport PATH=\"/usr/local/bin:/usr/bin:/bin\"\n\n# ✓ GOOD: Use absolute paths for critical commands\n/usr/bin/rm -rf \"$directory\"\n\n# ✗ BAD: Trusting user's PATH\nrm -rf \"$directory\" # What if there's a malicious 'rm' in PATH?\n```\n\n**Why:** Prevents PATH injection attacks.\n\n---\n\n## Summary\n\n**Most Critical Patterns:**\n\n1. Always quote variable expansions: `\"$var\"`\n2. Use `set -euo pipefail` for safety\n3. Prefer `[[ ]]` over `[ ]` in bash\n4. Use arrays for lists: `\"${array[@]}\"`\n5. Check command success: `if ! command; then`\n6. Use local variables in functions\n7. Errors to stderr: `echo \"Error\" >&2`\n8. Use `mktemp` for temporary files\n9. Cleanup with traps: `trap cleanup EXIT`\n10. Validate all user input\n\n**Most Dangerous Anti-Patterns:**\n\n1. Unquoted variables: `$var`\n2. Parsing `ls` output\n3. Using `eval` with user input\n4. Silencing errors without checking\n5. Not using `set -u` or defaults\n6. Global variables in functions\n7. Word splitting on filenames\n8. Testing strings with `>` for numbers\n9. `kill -9` without trying graceful shutdown\n10. Trusting user PATH\n\nFollowing these patterns and avoiding anti-patterns will result in robust, secure, and maintainable bash scripts.\n","content_type":"text/markdown; charset=utf-8","language":"markdown","size":20553,"content_sha256":"005d25d1708a26abed44a5feafe69816c79cfed691be5d5a27b80dbcb495137d"},{"filename":"references/platform_specifics.md","content":"# Platform-Specific Bash Scripting\n\nComprehensive guide to handling platform differences in bash scripts across Linux, macOS, Windows (Git Bash/WSL), and containers.\n\n---\n\n\n## ⚠️ WINDOWS GIT BASH / MINGW PATH CONVERSION\n\n**CRITICAL REFERENCE:** For complete Windows Git Bash path conversion and shell detection guidance, see:\n\n**📄 [windows-git-bash-paths.md](./windows-git-bash-paths.md)**\n\nThis comprehensive guide covers:\n- **Automatic path conversion behavior** (Unix → Windows)\n- **MSYS_NO_PATHCONV and MSYS2_ARG_CONV_EXCL** usage\n- **cygpath** manual conversion tool\n- **Shell detection methods** ($OSTYPE, uname, $MSYSTEM)\n- **Claude Code specific issues** (#2602 snapshot path conversion)\n- **Common problems and solutions**\n- **Cross-platform scripting patterns**\n\n**Git Bash path conversion is the #1 source of Windows bash scripting issues.** Always consult the dedicated guide when working with Windows/Git Bash.\n\n---\n\n## WARNING: WINDOWS GIT BASH / MINGW PATH CONVERSION\n\n**CRITICAL REFERENCE:** For complete Windows Git Bash path conversion and shell detection guidance, see:\n\n**[windows-git-bash-paths.md](./windows-git-bash-paths.md)**\n\nThis comprehensive guide covers:\n- **Automatic path conversion behavior** (Unix to Windows)\n- **MSYS_NO_PATHCONV and MSYS2_ARG_CONV_EXCL** usage\n- **cygpath** manual conversion tool\n- **Shell detection methods** ($OSTYPE, uname, $MSYSTEM)\n- **Claude Code specific issues** (#2602 snapshot path conversion)\n- **Common problems and solutions**\n- **Cross-platform scripting patterns**\n\n**Git Bash path conversion is the #1 source of Windows bash scripting issues.** Always consult the dedicated guide when working with Windows/Git Bash.\n\n---\n\n## Table of Contents\n\n1. [Platform Detection](#platform-detection)\n2. [Linux Specifics](#linux-specifics)\n3. [macOS Specifics](#macos-specifics)\n4. [Windows (Git Bash)](#windows-git-bash) - **See windows-git-bash-paths.md for complete guide** - **See windows-git-bash-paths.md for complete guide**\n5. [Windows (WSL)](#windows-wsl)\n6. [Container Environments](#container-environments)\n7. [Cross-Platform Patterns](#cross-platform-patterns)\n8. [Command Compatibility Matrix](#command-compatibility-matrix)\n\n---\n\n## 🚨 CRITICAL GUIDELINES\n\n### Windows File Path Requirements\n\n**MANDATORY: Always Use Backslashes on Windows for File Paths**\n\nWhen using Edit or Write tools on Windows, you MUST use backslashes (`\\`) in file paths, NOT forward slashes (`/`).\n\n**Examples:**\n- ❌ WRONG: `D:/repos/project/file.tsx`\n- ✅ CORRECT: `D:\\repos\\project\\file.tsx`\n\nThis applies to:\n- Edit tool file_path parameter\n- Write tool file_path parameter\n- All file operations on Windows systems\n\n\n### Documentation Guidelines\n\n**NEVER create new documentation files unless explicitly requested by the user.**\n\n- **Priority**: Update existing README.md files rather than creating new documentation\n- **Repository cleanliness**: Keep repository root clean - only README.md unless user requests otherwise\n- **Style**: Documentation should be concise, direct, and professional - avoid AI-generated tone\n- **User preference**: Only create additional .md files when user specifically asks for documentation\n\n\n---\n\n## Platform Detection\n\n### Comprehensive Detection Script\n\n```bash\n#!/usr/bin/env bash\n\ndetect_os() {\n case \"$OSTYPE\" in\n linux-gnu*)\n if grep -qi microsoft /proc/version 2>/dev/null; then\n echo \"wsl\"\n else\n echo \"linux\"\n fi\n ;;\n darwin*)\n echo \"macos\"\n ;;\n msys*|mingw*|cygwin*)\n echo \"gitbash\"\n ;;\n *)\n echo \"unknown\"\n ;;\n esac\n}\n\ndetect_distro() {\n # Only for Linux\n if [[ -f /etc/os-release ]]; then\n # shellcheck source=/dev/null\n source /etc/os-release\n echo \"$ID\"\n elif [[ -f /etc/redhat-release ]]; then\n echo \"rhel\"\n elif [[ -f /etc/debian_version ]]; then\n echo \"debian\"\n else\n echo \"unknown\"\n fi\n}\n\ndetect_container() {\n if [[ -f /.dockerenv ]]; then\n echo \"docker\"\n elif grep -q docker /proc/1/cgroup 2>/dev/null; then\n echo \"docker\"\n elif [[ -n \"$KUBERNETES_SERVICE_HOST\" ]]; then\n echo \"kubernetes\"\n else\n echo \"none\"\n fi\n}\n\n# Usage\nOS=$(detect_os)\nDISTRO=$(detect_distro)\nCONTAINER=$(detect_container)\n\necho \"OS: $OS\"\necho \"Distro: $DISTRO\"\necho \"Container: $CONTAINER\"\n```\n\n### Environment Variables for Detection\n\n```bash\n# Check various environment indicators\ncheck_environment() {\n echo \"OSTYPE: $OSTYPE\"\n echo \"MACHTYPE: $MACHTYPE\"\n echo \"HOSTTYPE: $HOSTTYPE\"\n\n # Kernel info\n uname -s # Operating system name\n uname -r # Kernel release\n uname -m # Machine hardware\n uname -p # Processor type\n\n # More detailed\n uname -a # All information\n}\n\n# Platform-specific variables\n# Linux: OSTYPE=linux-gnu\n# macOS: OSTYPE=darwin20.0\n# Git Bash: OSTYPE=msys\n# Cygwin: OSTYPE=cygwin\n# WSL: OSTYPE=linux-gnu (but with Microsoft in /proc/version)\n```\n\n---\n\n## Linux Specifics\n\n### Linux-Only Features\n\n```bash\n# /proc filesystem\nget_process_info() {\n local pid=$1\n\n if [[ -d \"/proc/$pid\" ]]; then\n echo \"Command: $(cat /proc/$pid/cmdline | tr '\\0' ' ')\"\n echo \"Working dir: $(readlink /proc/$pid/cwd)\"\n echo \"Executable: $(readlink /proc/$pid/exe)\"\n fi\n}\n\n# systemd\ncheck_systemd() {\n if command -v systemctl &> /dev/null; then\n systemctl status my-service\n systemctl is-active my-service\n systemctl is-enabled my-service\n fi\n}\n\n# cgroups\ncheck_cgroups() {\n if [[ -d /sys/fs/cgroup ]]; then\n cat /sys/fs/cgroup/memory/memory.limit_in_bytes\n fi\n}\n\n# inotify for file watching\nwatch_directory() {\n if command -v inotifywait &> /dev/null; then\n inotifywait -m -r -e modify,create,delete /path/to/watch\n fi\n}\n```\n\n### Distribution-Specific Commands\n\n```bash\n# Package management\ninstall_package() {\n local package=$1\n\n if command -v apt-get &> /dev/null; then\n # Debian/Ubuntu\n sudo apt-get update\n sudo apt-get install -y \"$package\"\n elif command -v yum &> /dev/null; then\n # RHEL/CentOS\n sudo yum install -y \"$package\"\n elif command -v dnf &> /dev/null; then\n # Fedora\n sudo dnf install -y \"$package\"\n elif command -v pacman &> /dev/null; then\n # Arch\n sudo pacman -S --noconfirm \"$package\"\n elif command -v zypper &> /dev/null; then\n # openSUSE\n sudo zypper install -y \"$package\"\n elif command -v apk &> /dev/null; then\n # Alpine\n sudo apk add \"$package\"\n else\n echo \"Error: No supported package manager found\" >&2\n return 1\n fi\n}\n\n# Service management\nmanage_service() {\n local action=$1\n local service=$2\n\n if command -v systemctl &> /dev/null; then\n # systemd (most modern distros)\n sudo systemctl \"$action\" \"$service\"\n elif command -v service &> /dev/null; then\n # SysV init\n sudo service \"$service\" \"$action\"\n else\n echo \"Error: No supported service manager found\" >&2\n return 1\n fi\n}\n```\n\n### GNU Coreutils (Linux Standard)\n\n```bash\n# GNU-specific features\n# These work on Linux but may not work on macOS/BSD\n\n# sed with -i (in-place editing)\nsed -i 's/old/new/g' file.txt # Linux\nsed -i '' 's/old/new/g' file.txt # macOS requires empty string\n\n# date with flexible parsing\ndate -d \"yesterday\" +%Y-%m-%d # Linux\ndate -v-1d +%Y-%m-%d # macOS\n\n# stat with -c format\nstat -c \"%s\" file.txt # Linux (file size)\nstat -f \"%z\" file.txt # macOS\n\n# readlink with -f (canonicalize)\nreadlink -f /path/to/file # Linux\n# macOS doesn't have -f, use greadlink or:\npython -c \"import os; print(os.path.realpath('$file'))\"\n\n# GNU find with -printf\nfind . -type f -printf \"%p %s\\n\" # Linux\nfind . -type f -exec stat -f \"%N %z\" {} \\; # macOS\n```\n\n---\n\n## macOS Specifics\n\n### BSD vs GNU Commands\n\n```bash\n# Detect and use GNU versions if available\nsetup_commands_macos() {\n # Install GNU commands: brew install coreutils gnu-sed gnu-tar findutils\n if command -v gsed &> /dev/null; then\n SED=gsed\n else\n SED=sed\n fi\n\n if command -v ggrep &> /dev/null; then\n GREP=ggrep\n else\n GREP=grep\n fi\n\n if command -v greadlink &> /dev/null; then\n READLINK=greadlink\n else\n READLINK=readlink\n fi\n\n if command -v gdate &> /dev/null; then\n DATE=gdate\n else\n DATE=date\n fi\n\n if command -v gstat &> /dev/null; then\n STAT=gstat\n else\n STAT=stat\n fi\n\n export SED GREP READLINK DATE STAT\n}\n\n# Usage\nsetup_commands_macos\n$SED -i 's/old/new/g' file.txt # Works on both platforms\n```\n\n### macOS-Specific Features\n\n```bash\n# macOS filesystem (case-insensitive by default on APFS/HFS+)\ncheck_case_sensitivity() {\n touch /tmp/test_case\n if [[ -f /tmp/TEST_CASE ]]; then\n echo \"Filesystem is case-insensitive\"\n else\n echo \"Filesystem is case-sensitive\"\n fi\n rm -f /tmp/test_case /tmp/TEST_CASE\n}\n\n# macOS extended attributes\n# Set extended attribute\nxattr -w com.example.myattr \"value\" file.txt\n\n# Get extended attribute\nxattr -p com.example.myattr file.txt\n\n# List all extended attributes\nxattr -l file.txt\n\n# Remove extended attribute\nxattr -d com.example.myattr file.txt\n\n# macOS Spotlight\n# Disable indexing for directory\nmdutil -i off /path/to/directory\n\n# Search with mdfind (Spotlight from command line)\nmdfind \"kMDItemFSName == 'filename.txt'\"\n\n# macOS clipboard\n# Copy to clipboard\necho \"text\" | pbcopy\n\n# Paste from clipboard\npbpaste\n\n# macOS notifications\n# Display notification\nosascript -e 'display notification \"Build complete\" with title \"Build Status\"'\n\n# macOS open command\n# Open file with default application\nopen file.pdf\n\n# Open URL\nopen https://example.com\n\n# Open current directory in Finder\nopen .\n```\n\n### Homebrew Package Management\n\n```bash\n# Check if Homebrew is installed\nif command -v brew &> /dev/null; then\n # Install package\n brew install package-name\n\n # Update Homebrew\n brew update\n\n # Upgrade packages\n brew upgrade\n\n # Search for package\n brew search package-name\n\n # Get package info\n brew info package-name\nfi\n```\n\n---\n\n## Windows (Git Bash)\n\n### Git Bash Environment\n\n```bash\n# Git Bash uses MSYS2 runtime\n# Provides Unix-like environment on Windows\n\n# Path handling\nconvert_path() {\n local path=$1\n\n if command -v cygpath &> /dev/null; then\n # Convert Unix path to Windows\n windows_path=$(cygpath -w \"$path\")\n echo \"$windows_path\"\n\n # Convert Windows path to Unix\n unix_path=$(cygpath -u \"C:\\\\Users\\\\user\\\\file.txt\")\n echo \"$unix_path\"\n else\n # Manual conversion (Git Bash)\n # /c/Users/user → C:\\Users\\user\n echo \"${path//\\//\\\\}\" | sed 's/^\\\\//'\n fi\n}\n\n# Git Bash path conventions\n# C:\\Users\\user → /c/Users/user\n# D:\\data → /d/data\n\n# Home directory\necho \"$HOME\" # /c/Users/username\necho \"$USERPROFILE\" # Windows-style path\n\n# Temp directory\necho \"$TEMP\" # Windows temp\necho \"$TMP\" # Windows temp\necho \"/tmp\" # Git Bash temp (usually C:\\Users\\username\\AppData\\Local\\Temp)\n```\n\n### Limited Features in Git Bash\n\n```bash\n# Features NOT available in Git Bash:\n\n# 1. No systemd\n# Use Windows services instead:\n# sc query ServiceName\n# net start ServiceName\n\n# 2. Limited signal support\n# SIGTERM works, but some signals behave differently\n\n# 3. No /proc filesystem\n# Use wmic or PowerShell:\n# wmic process get processid,commandline\n\n# 4. Process handling differences\n# ps command is available but limited\nps -W # Show Windows processes\n\n# 5. File permissions are simulated\n# chmod works but doesn't map directly to Windows ACLs\n\n# 6. Symbolic links require administrator privileges\n# Or Developer Mode enabled in Windows 10+\n```\n\n### Windows-Specific Workarounds\n\n```bash\n# Run PowerShell commands from Git Bash\nrun_powershell() {\n local command=$1\n powershell.exe -Command \"$command\"\n}\n\n# Example: Get Windows version\nrun_powershell \"Get-ComputerInfo | Select-Object WindowsVersion\"\n\n# Run cmd.exe commands\nrun_cmd() {\n local command=$1\n cmd.exe /c \"$command\"\n}\n\n# Example: Set Windows environment variable\nrun_cmd \"setx MY_VAR value\"\n\n# Check if running with admin privileges\nis_admin() {\n net session &> /dev/null\n return $?\n}\n\nif is_admin; then\n echo \"Running with administrator privileges\"\nelse\n echo \"Not running as administrator\"\nfi\n\n# Windows line endings (CRLF vs LF)\nfix_line_endings() {\n local file=$1\n\n # Convert CRLF to LF\n dos2unix \"$file\"\n\n # Or with sed\n sed -i 's/\\r$//' \"$file\"\n\n # Convert LF to CRLF\n unix2dos \"$file\"\n\n # Or with sed\n sed -i 's/$/\\r/' \"$file\"\n}\n```\n\n### Git Bash Best Practices\n\n```bash\n# Always handle spaces in Windows paths\nprocess_file() {\n local file=\"$1\" # Always quote!\n\n # Windows paths often have spaces\n # C:\\Program Files\\...\n}\n\n# Use forward slashes when possible\ncd /c/Program\\ Files/Git # Works\ncd \"C:\\Program Files\\Git\" # Also works, but...\ncd C:\\\\Program\\ Files\\\\Git # Avoid\n\n# Set Git config for line endings\ngit config --global core.autocrlf true # Windows\ngit config --global core.autocrlf input # Linux/macOS\n\n# Check Git Bash version\nbash --version\nuname -a # Shows MINGW or MSYS\n```\n\n---\n\n## Windows (WSL)\n\n### WSL1 vs WSL2\n\n```bash\n# Detect WSL version\ndetect_wsl_version() {\n if grep -qi microsoft /proc/version; then\n if [[ $(uname -r) =~ microsoft ]]; then\n echo \"WSL 1\"\n elif [[ $(uname -r) =~ WSL2 ]]; then\n echo \"WSL 2\"\n else\n # Check kernel version\n if [[ $(uname -r) =~ ^4\\. ]]; then\n echo \"WSL 1\"\n else\n echo \"WSL 2\"\n fi\n fi\n else\n echo \"Not WSL\"\n fi\n}\n\n# WSL1 limitations:\n# - No full syscall compatibility\n# - File I/O slower on Windows filesystem\n# - No Docker/containers (needs WSL2)\n\n# WSL2 improvements:\n# - Full Linux kernel\n# - Better filesystem performance\n# - Docker/container support\n# - Near-native Linux performance\n```\n\n### Windows Filesystem Access\n\n```bash\n# Access Windows drives from WSL\n# Mounted at /mnt/c, /mnt/d, etc.\n\n# List Windows drives\nls /mnt/\n\n# Access Windows user directory\nWINDOWS_HOME=\"/mnt/c/Users/$USER\"\ncd \"$WINDOWS_HOME\"\n\n# File permissions on Windows filesystem\n# Files on /mnt/c are owned by root but accessible\n# Permissions are simulated\n\n# Best practice: Use WSL filesystem for Linux files\n# Use /home/username, not /mnt/c/...\n# Much faster, especially in WSL1\n```\n\n### WSL Interoperability\n\n```bash\n# Run Windows executables from WSL\n# .exe files are automatically executable\n\n# Run Windows commands\ncmd.exe /c dir\nnotepad.exe file.txt\nexplorer.exe . # Open current directory in Windows Explorer\n\n# Run PowerShell\npowershell.exe -Command \"Get-Date\"\n\n# Pipe between Linux and Windows\ncat file.txt | clip.exe # Copy to Windows clipboard\n\n# Environment variables\n# Windows environment is accessible with WSLENV\n\n# Share environment variable from Windows to WSL\n# In PowerShell:\n# $env:WSLENV = \"MYVAR/p\"\n# This converts Windows paths to WSL paths\n```\n\n### WSL-Specific Configuration\n\n```bash\n# /etc/wsl.conf configuration\ncat > /etc/wsl.conf \u003c\u003c 'EOF'\n[automount]\nenabled = true\nroot = /mnt/\noptions = \"metadata,umask=22,fmask=11\"\n\n[network]\ngenerateHosts = true\ngenerateResolvConf = true\n\n[interop]\nenabled = true\nappendWindowsPath = true\nEOF\n\n# Apply: wsl.exe --shutdown (from PowerShell)\n\n# Network differences\n# WSL1: Shares network with Windows\n# WSL2: NAT network, different IP\n\n# Get WSL IP address\nip addr show eth0 | grep -oP '(?\u003c=inet\\s)\\d+(\\.\\d+){3}'\n\n# Access Windows services from WSL2\n# Use Windows IP, not localhost\n# Or use: localhost (WSL2 has localhost forwarding)\n```\n\n---\n\n## Container Environments\n\n### Docker Considerations\n\n```bash\n# Minimal base images often lack bash\n# alpine: Only has /bin/sh by default\n# debian:slim: Has bash\n# ubuntu: Has bash\n\n# Check if bash is available\nif [ -f /bin/bash ]; then\n exec /bin/bash \"$@\"\nelse\n exec /bin/sh \"$@\"\nfi\n\n# Container detection\nis_docker() {\n if [[ -f /.dockerenv ]] || grep -q docker /proc/1/cgroup 2>/dev/null; then\n return 0\n else\n return 1\n fi\n}\n\n# PID 1 problem in containers\n# Your script might be PID 1, which means:\n# - Zombie process reaping is your responsibility\n# - Signals behave differently\n\n# Solution: Use tini or dumb-init\n# Or handle signals explicitly\nhandle_sigterm() {\n # Forward to child processes\n kill -TERM \"$child_pid\" 2>/dev/null\n wait \"$child_pid\"\n exit 0\n}\n\ntrap handle_sigterm SIGTERM\n\n# Start main process\nmain_process &\nchild_pid=$!\nwait \"$child_pid\"\n```\n\n### Kubernetes Considerations\n\n```bash\n# Kubernetes-specific environment variables\nif [[ -n \"$KUBERNETES_SERVICE_HOST\" ]]; then\n echo \"Running in Kubernetes\"\n\n # Access Kubernetes API\n KUBE_TOKEN=$(cat /var/run/secrets/kubernetes.io/serviceaccount/token)\n KUBE_CA=/var/run/secrets/kubernetes.io/serviceaccount/ca.crt\n\n # Get pod name\n POD_NAME=${POD_NAME:-$(hostname)}\n\n # Get namespace\n NAMESPACE=$(cat /var/run/secrets/kubernetes.io/serviceaccount/namespace)\nfi\n\n# Health checks\n# Kubernetes expects:\n# - HTTP probe on specific port\n# - Or command that exits 0 for success\n\n# Liveness probe handler\nhandle_health_check() {\n # Check if application is healthy\n if check_health; then\n exit 0\n else\n exit 1\n fi\n}\n\n# Readiness probe handler\nhandle_readiness_check() {\n # Check if ready to serve traffic\n if is_ready; then\n exit 0\n else\n exit 1\n fi\n}\n\n# Graceful shutdown for rolling updates\n# Kubernetes sends SIGTERM, waits (default 30s), then SIGKILL\ntrap 'graceful_shutdown' SIGTERM\n\ngraceful_shutdown() {\n echo \"Received SIGTERM, shutting down gracefully...\"\n\n # Stop accepting new connections\n # Finish processing existing requests\n # Close connections\n # Exit\n\n exit 0\n}\n```\n\n### Container Best Practices\n\n```bash\n# Don't assume specific users/groups exist\n# Many containers run as non-root or random UID\n\n# Check current user\nif [[ $EUID -eq 0 ]]; then\n echo \"Running as root\"\nelse\n echo \"Running as user $EUID\"\nfi\n\n# Handle arbitrary UIDs (OpenShift)\n# Files in mounted volumes may not be owned by container user\n# Solution: Add current user to group, use group permissions\n\n# Minimal dependencies\n# Container images should be small\n# Don't install unnecessary packages\n\n# Use absolute paths or set PATH explicitly\nexport PATH=/usr/local/bin:/usr/bin:/bin\n\n# Environment variables for configuration\n# Don't hardcode values, use env vars\nDATABASE_URL=${DATABASE_URL:-postgres://localhost/db}\n\n# Logging to stdout/stderr\n# Container orchestrators capture these\necho \"Log message\" # To stdout\necho \"Error message\" >&2 # To stderr\n\n# Don't write to filesystem (except for tmpfs)\n# Containers are ephemeral\n# Use volumes for persistent data\n```\n\n---\n\n## Cross-Platform Patterns\n\n### Portable Command Wrapper\n\n```bash\n# Create wrappers for platform-specific commands\nsetup_portable_commands() {\n local os\n os=$(detect_os)\n\n case \"$os\" in\n linux)\n SED=sed\n READLINK=\"readlink -f\"\n DATE=date\n STAT=\"stat -c\"\n GREP=grep\n ;;\n macos)\n # Prefer GNU versions if available\n SED=$(command -v gsed || echo sed)\n READLINK=$(command -v greadlink || echo \"echo\") # No -f on BSD\n DATE=$(command -v gdate || echo date)\n STAT=$(command -v gstat || echo stat)\n GREP=$(command -v ggrep || echo grep)\n ;;\n gitbash)\n SED=sed\n READLINK=readlink # Git Bash has GNU tools\n DATE=date\n STAT=stat\n GREP=grep\n ;;\n esac\n\n export SED READLINK DATE STAT GREP\n}\n\n# Use the wrappers\nsetup_portable_commands\n$SED -i 's/old/new/g' file.txt\n```\n\n### Cross-Platform Temp Files\n\n```bash\n# Portable temporary file creation\ncreate_temp_file() {\n # Works on all platforms\n local temp_file\n temp_file=$(mktemp) || {\n # Fallback if mktemp doesn't exist\n temp_file=\"/tmp/script.$.$RANDOM\"\n touch \"$temp_file\"\n }\n\n echo \"$temp_file\"\n}\n\n# Portable temporary directory\ncreate_temp_dir() {\n local temp_dir\n temp_dir=$(mktemp -d) || {\n # Fallback\n temp_dir=\"/tmp/script.$.$RANDOM\"\n mkdir -p \"$temp_dir\"\n }\n\n echo \"$temp_dir\"\n}\n\n# Clean up temp files on exit\nTEMP_DIR=$(create_temp_dir)\ntrap 'rm -rf \"$TEMP_DIR\"' EXIT\n```\n\n### Cross-Platform File Paths\n\n```bash\n# Normalize paths across platforms\nnormalize_path() {\n local path=\"$1\"\n\n # Remove trailing slashes\n path=\"${path%/}\"\n\n # Convert backslashes to forward slashes (Windows)\n path=\"${path//\\\\//}\"\n\n # Resolve . and ..\n # Use Python for reliable normalization\n if command -v python3 &> /dev/null; then\n path=$(python3 -c \"import os; print(os.path.normpath('$path'))\")\n elif command -v python &> /dev/null; then\n path=$(python -c \"import os; print(os.path.normpath('$path'))\")\n fi\n\n echo \"$path\"\n}\n\n# Get absolute path (cross-platform)\nget_absolute_path() {\n local path=\"$1\"\n\n # Try readlink -f (Linux, Git Bash)\n if readlink -f \"$path\" &> /dev/null; then\n readlink -f \"$path\"\n # Try realpath (most platforms)\n elif command -v realpath &> /dev/null; then\n realpath \"$path\"\n # Fallback to Python\n elif command -v python3 &> /dev/null; then\n python3 -c \"import os; print(os.path.abspath('$path'))\"\n # Fallback to cd\n elif [[ -d \"$path\" ]]; then\n (cd \"$path\" && pwd)\n else\n (cd \"$(dirname \"$path\")\" && echo \"$(pwd)/$(basename \"$path\")\")\n fi\n}\n```\n\n### Cross-Platform Process Management\n\n```bash\n# Find process by name (cross-platform)\nfind_process() {\n local process_name=\"$1\"\n\n if command -v pgrep &> /dev/null; then\n pgrep -f \"$process_name\"\n else\n ps aux | grep \"$process_name\" | grep -v grep | awk '{print $2}'\n fi\n}\n\n# Kill process by name (cross-platform)\nkill_process() {\n local process_name=\"$1\"\n\n if command -v pkill &> /dev/null; then\n pkill -f \"$process_name\"\n else\n local pids\n pids=$(find_process \"$process_name\")\n if [[ -n \"$pids\" ]]; then\n kill $pids\n fi\n fi\n}\n```\n\n---\n\n## Command Compatibility Matrix\n\n| Command | Linux | macOS | Git Bash | Notes |\n|---------|-------|-------|----------|-------|\n| `sed -i` | ✓ | ✓* | ✓ | macOS needs `sed -i ''` |\n| `date -d` | ✓ | ✗ | ✓ | macOS uses `-v` |\n| `readlink -f` | ✓ | ✗ | ✓ | macOS needs `greadlink` |\n| `stat -c` | ✓ | ✗ | ✓ | macOS uses `-f` |\n| `grep -P` | ✓ | ✗ | ✓ | macOS doesn't support PCRE |\n| `find -printf` | ✓ | ✗ | ✓ | macOS doesn't have `-printf` |\n| `xargs -r` | ✓ | ✗ | ✓ | macOS doesn't have `-r` |\n| `ps aux` | ✓ | ✓ | ✓* | Git Bash has limited output |\n| `ls --color` | ✓ | ✗ | ✓ | macOS uses `-G` |\n| `du -b` | ✓ | ✗ | ✓ | macOS doesn't support bytes |\n| `mktemp` | ✓ | ✓ | ✓ | Works on all platforms |\n| `timeout` | ✓ | ✗ | ✓ | macOS needs `gtimeout` |\n\n**Legend:**\n- ✓ = Supported\n- ✗ = Not supported\n- ✓* = Supported with limitations\n\n---\n\n## Testing Across Platforms\n\n```bash\n# Test script on multiple platforms\ntest_platforms() {\n local script=\"$1\"\n\n echo \"Testing on current platform: $(detect_os)\"\n bash -n \"$script\" || {\n echo \"Syntax error!\"\n return 1\n }\n\n # Run ShellCheck\n if command -v shellcheck &> /dev/null; then\n shellcheck \"$script\" || return 1\n fi\n\n # Run the script\n bash \"$script\" || return 1\n\n echo \"Tests passed on $(detect_os)\"\n}\n\n# CI/CD matrix testing\n# Use GitHub Actions, GitLab CI, etc. to test on multiple platforms\n```\n\n**Example GitHub Actions matrix:**\n```yaml\njobs:\n test:\n runs-on: ${{ matrix.os }}\n strategy:\n matrix:\n os: [ubuntu-latest, macos-latest, windows-latest]\n steps:\n - uses: actions/checkout@v3\n - name: Test script\n run: bash test.sh\n```\n\n---\n\n## Summary\n\n**Key takeaways for cross-platform bash scripts:**\n\n1. **Always detect the platform** before using platform-specific features\n2. **Use portable commands** or provide fallbacks\n3. **Test on all target platforms** (CI/CD with matrix builds)\n4. **Avoid platform-specific assumptions** (file paths, users, services)\n5. **Use ShellCheck** to catch portability issues\n6. **Prefer POSIX compliance** when possible for maximum portability\n7. **Document platform requirements** in script comments\n8. **Provide GNU alternatives** on macOS when needed\n9. **Handle path differences** carefully (especially Windows)\n10. **Test in containers** if that's your deployment target\n\nFor maximum portability: stick to POSIX shell (`#!/bin/sh`) and avoid bashisms unless you control the deployment environment.\n","content_type":"text/markdown; charset=utf-8","language":"markdown","size":25183,"content_sha256":"6c95018d53c48c0c00f57826e1e12b7a123a6ff62560fcd72b9fb7055e79f480"},{"filename":"references/resources.md","content":"# Bash Scripting Resources\n\nComprehensive directory of authoritative sources, tools, and learning resources for bash scripting.\n\n---\n\n## Table of Contents\n\n1. [Official Documentation](#official-documentation)\n2. [Style Guides and Standards](#style-guides-and-standards)\n3. [Tools and Utilities](#tools-and-utilities)\n4. [Learning Resources](#learning-resources)\n5. [Community Resources](#community-resources)\n6. [Books](#books)\n7. [Cheat Sheets and Quick References](#cheat-sheets-and-quick-references)\n8. [Testing and Quality](#testing-and-quality)\n9. [Platform-Specific Resources](#platform-specific-resources)\n10. [Advanced Topics](#advanced-topics)\n\n---\n\n## 🚨 CRITICAL GUIDELINES\n\n### Windows File Path Requirements\n\n**MANDATORY: Always Use Backslashes on Windows for File Paths**\n\nWhen using Edit or Write tools on Windows, you MUST use backslashes (`\\`) in file paths, NOT forward slashes (`/`).\n\n**Examples:**\n- ❌ WRONG: `D:/repos/project/file.tsx`\n- ✅ CORRECT: `D:\\repos\\project\\file.tsx`\n\nThis applies to:\n- Edit tool file_path parameter\n- Write tool file_path parameter\n- All file operations on Windows systems\n\n\n### Documentation Guidelines\n\n**NEVER create new documentation files unless explicitly requested by the user.**\n\n- **Priority**: Update existing README.md files rather than creating new documentation\n- **Repository cleanliness**: Keep repository root clean - only README.md unless user requests otherwise\n- **Style**: Documentation should be concise, direct, and professional - avoid AI-generated tone\n- **User preference**: Only create additional .md files when user specifically asks for documentation\n\n\n---\n\n## Official Documentation\n\n### Bash Manual\n\n**GNU Bash Reference Manual**\n- **URL:** https://www.gnu.org/software/bash/manual/\n- **Description:** The authoritative reference for bash features, syntax, and built-ins\n- **Use for:** Detailed feature documentation, syntax clarification, version-specific features\n\n**Bash Man Page**\n```bash\nman bash # Complete bash documentation\nman bash-builtins # Built-in commands\n```\n- **Use for:** Quick reference on local system, offline documentation\n\n### POSIX Standards\n\n**POSIX Shell Command Language**\n- **URL:** https://pubs.opengroup.org/onlinepubs/9699919799/utilities/V3_chap02.html\n- **Description:** IEEE/Open Group specification for portable shell scripting\n- **Use for:** Writing portable scripts, understanding sh vs bash differences\n\n**POSIX Utilities**\n- **URL:** https://pubs.opengroup.org/onlinepubs/9699919799/idx/utilities.html\n- **Description:** Standard utilities available in POSIX-compliant systems\n- **Use for:** Portable command usage, cross-platform compatibility\n\n### Command Documentation\n\n**GNU Coreutils Manual**\n- **URL:** https://www.gnu.org/software/coreutils/manual/\n- **Description:** Documentation for core GNU utilities (ls, cat, grep, etc.)\n- **Use for:** Understanding Linux command behavior, GNU-specific features\n\n**Man Pages Online**\n- **URL:** https://man7.org/linux/man-pages/\n- **URL:** https://www.freebsd.org/cgi/man.cgi (BSD/macOS)\n- **Description:** Online searchable man pages\n- **Use for:** Quick online reference, comparing Linux vs BSD commands\n\n---\n\n## Style Guides and Standards\n\n### Google Shell Style Guide\n\n**URL:** https://google.github.io/styleguide/shellguide.html\n\n**Key Points:**\n- Industry-standard practices from Google\n- Covers naming conventions, formatting, best practices\n- When to use shell vs other languages\n- Safety and portability guidelines\n\n**Use for:** Professional code style, team standards, code reviews\n\n### Defensive Bash Programming\n\n**URL:** https://kfirlavi.herokuapp.com/blog/2012/11/14/defensive-bash-programming\n\n**Key Points:**\n- Writing robust bash scripts\n- Error handling patterns\n- Safe coding practices\n- Code organization\n\n**Use for:** Improving script reliability, avoiding common pitfalls\n\n### Shell Style Guide (GitHub)\n\n**URL:** https://github.com/bahamas10/bash-style-guide\n\n**Key Points:**\n- Community-driven style guidelines\n- Practical examples\n- Modern bash features\n\n**Use for:** Alternative perspectives on style, community standards\n\n---\n\n## Tools and Utilities\n\n### ShellCheck\n\n**Website:** https://www.shellcheck.net/\n**GitHub:** https://github.com/koalaman/shellcheck\n**Online Tool:** https://www.shellcheck.net/ (paste code for instant feedback)\n\n**Description:** Static analysis tool for shell scripts\n\n**Installation:**\n```bash\n# Ubuntu/Debian\napt-get install shellcheck\n\n# macOS\nbrew install shellcheck\n\n# Windows (Scoop)\nscoop install shellcheck\n\n# Via Docker\ndocker run --rm -v \"$PWD:/mnt\" koalaman/shellcheck script.sh\n```\n\n**Usage:**\n```bash\nshellcheck script.sh # Check script\nshellcheck -x script.sh # Follow source statements\nshellcheck -f json script.sh # JSON output\nshellcheck -e SC2086 script.sh # Exclude specific warnings\n```\n\n**ShellCheck Wiki:** https://www.shellcheck.net/wiki/\n- Detailed explanations of every warning\n- **Use for:** Understanding and fixing ShellCheck warnings\n\n### shfmt\n\n**GitHub:** https://github.com/mvdan/sh\n\n**Description:** Shell script formatter\n\n**Installation:**\n```bash\n# macOS\nbrew install shfmt\n\n# Go\ngo install mvdan.cc/sh/v3/cmd/shfmt@latest\n```\n\n**Usage:**\n```bash\nshfmt -i 4 -w script.sh # Format with 4-space indent\nshfmt -d script.sh # Show diff without modifying\nshfmt -l script.sh # List files that would be changed\n```\n\n**Use for:** Consistent code formatting, automated formatting in CI\n\n### BATS (Bash Automated Testing System)\n\n**GitHub:** https://github.com/bats-core/bats-core\n\n**Description:** Testing framework for bash scripts\n\n**Installation:**\n```bash\ngit clone https://github.com/bats-core/bats-core.git\ncd bats-core\n./install.sh /usr/local\n```\n\n**Usage:**\n```bash\nbats test/ # Run all tests\nbats test/script.bats # Run specific test file\nbats --tap test/ # TAP output format\n```\n\n**Documentation:** https://bats-core.readthedocs.io/\n\n**Use for:** Unit testing bash scripts, CI/CD integration\n\n### bashate\n\n**GitHub:** https://github.com/openstack/bashate\n\n**Description:** Style checker (used by OpenStack)\n\n**Installation:**\n```bash\npip install bashate\n```\n\n**Usage:**\n```bash\nbashate script.sh\nbashate -i E006 script.sh # Ignore specific errors\n```\n\n**Use for:** Additional style checking beyond ShellCheck\n\n### checkbashisms\n\n**Package:** devscripts (Debian)\n\n**Description:** Checks for bashisms in sh scripts\n\n**Installation:**\n```bash\napt-get install devscripts # Ubuntu/Debian\n```\n\n**Usage:**\n```bash\ncheckbashisms script.sh\ncheckbashisms -f script.sh # Force check even if #!/bin/bash\n```\n\n**Use for:** Ensuring POSIX compliance, portable scripts\n\n---\n\n## Learning Resources\n\n### Interactive Tutorials\n\n**Bash Academy**\n- **URL:** https://www.bash.academy/\n- **Description:** Modern, comprehensive bash tutorial\n- **Topics:** Basics, scripting, advanced features\n- **Use for:** Learning bash from scratch, structured learning path\n\n**Learn Shell**\n- **URL:** https://www.learnshell.org/\n- **Description:** Interactive bash tutorial with exercises\n- **Use for:** Hands-on practice, beginners\n\n**Bash Scripting Tutorial**\n- **URL:** https://linuxconfig.org/bash-scripting-tutorial\n- **Description:** Comprehensive tutorial series\n- **Use for:** Step-by-step learning, examples\n\n### Guides and Documentation\n\n**Bash Guide for Beginners**\n- **URL:** https://tldp.org/LDP/Bash-Beginners-Guide/html/\n- **Author:** The Linux Documentation Project\n- **Description:** Comprehensive guide covering basics to intermediate\n- **Use for:** Structured learning, reference material\n\n**Advanced Bash-Scripting Guide**\n- **URL:** https://tldp.org/LDP/abs/html/\n- **Description:** In-depth coverage of advanced bash topics\n- **Topics:** Complex scripting, text processing, system administration\n- **Use for:** Advanced techniques, real-world examples\n\n**Bash Hackers Wiki**\n- **URL:** https://wiki.bash-hackers.org/\n- **Alternative:** https://flokoe.github.io/bash-hackers-wiki/ (maintained mirror)\n- **Description:** Community-driven bash documentation\n- **Use for:** In-depth explanations, advanced topics, edge cases\n\n**Greg's Wiki (Wooledge)**\n- **URL:** https://mywiki.wooledge.org/\n- **Key Pages:**\n - https://mywiki.wooledge.org/BashFAQ\n - https://mywiki.wooledge.org/BashPitfalls\n - https://mywiki.wooledge.org/BashGuide\n- **Description:** High-quality bash Q&A and guides\n- **Use for:** Common questions, avoiding pitfalls, best practices\n\n### Video Courses\n\n**Bash Scripting on Linux (Udemy)**\n- **Description:** Comprehensive video course\n- **Use for:** Visual learners\n\n**Shell Scripting: Discover How to Automate Command Line Tasks (Udemy)**\n- **Description:** Practical shell scripting course\n- **Use for:** Automation-focused learning\n\n**LinkedIn Learning - Learning Bash Scripting**\n- **Description:** Professional development course\n- **Use for:** Structured corporate training\n\n---\n\n## Community Resources\n\n### Stack Overflow\n\n**Bash Tag**\n- **URL:** https://stackoverflow.com/questions/tagged/bash\n- **Use for:** Specific problems, code review, troubleshooting\n\n**Top Questions:**\n- **URL:** https://stackoverflow.com/questions/tagged/bash?tab=Votes\n- **Use for:** Common problems and solutions\n\n### Unix & Linux Stack Exchange\n\n**URL:** https://unix.stackexchange.com/\n\n**Shell Tag:** https://unix.stackexchange.com/questions/tagged/shell\n**Bash Tag:** https://unix.stackexchange.com/questions/tagged/bash\n\n**Use for:** Unix/Linux-specific questions, system administration\n\n### Reddit\n\n**/r/bash**\n- **URL:** https://www.reddit.com/r/bash/\n- **Description:** Bash scripting community\n- **Use for:** Discussions, learning resources, help\n\n**/r/commandline**\n- **URL:** https://www.reddit.com/r/commandline/\n- **Description:** Command-line interface community\n- **Use for:** CLI tips, tools, productivity\n\n### IRC/Chat\n\n**Freenode #bash**\n- **URL:** irc://irc.freenode.net/bash\n- **Description:** Real-time bash help channel\n- **Use for:** Live help, quick questions\n\n**Libera.Chat #bash**\n- **URL:** irc://irc.libera.chat/bash\n- **Description:** Alternative IRC channel\n- **Use for:** Live community support\n\n---\n\n## Books\n\n### \"Classic Shell Scripting\" by Arnold Robbins & Nelson Beebe\n\n**Publisher:** O'Reilly\n**ISBN:** 978-0596005955\n\n**Topics:**\n- Shell basics and portability\n- Text processing and filters\n- Shell programming patterns\n\n**Use for:** Comprehensive reference, professional development\n\n### \"Learning the bash Shell\" by Cameron Newham\n\n**Publisher:** O'Reilly\n**ISBN:** 978-0596009656\n\n**Topics:**\n- Bash basics\n- Command-line editing\n- Shell programming\n\n**Use for:** Systematic learning, reference\n\n### \"Bash Cookbook\" by Carl Albing & JP Vossen\n\n**Publisher:** O'Reilly\n**ISBN:** 978-1491975336\n\n**Topics:**\n- Solutions to common problems\n- Recipes and patterns\n- Real-world examples\n\n**Use for:** Problem-solving, practical examples\n\n### \"Wicked Cool Shell Scripts\" by Dave Taylor & Brandon Perry\n\n**Publisher:** No Starch Press\n**ISBN:** 978-1593276027\n\n**Topics:**\n- Creative shell scripting\n- System administration\n- Fun and practical scripts\n\n**Use for:** Inspiration, practical applications\n\n### \"The Linux Command Line\" by William Shotts\n\n**Publisher:** No Starch Press\n**ISBN:** 978-1593279523\n**Free PDF:** https://linuxcommand.org/tlcl.php\n\n**Topics:**\n- Command-line basics\n- Shell scripting fundamentals\n- Linux system administration\n\n**Use for:** Beginners, comprehensive introduction\n\n---\n\n## Cheat Sheets and Quick References\n\n### Bash Cheat Sheet (DevHints)\n\n**URL:** https://devhints.io/bash\n\n**Content:**\n- Quick syntax reference\n- Common patterns\n- Parameter expansion\n- Conditionals and loops\n\n**Use for:** Quick lookups, syntax reminders\n\n### Bash Scripting Cheat Sheet (GitHub)\n\n**URL:** https://github.com/LeCoupa/awesome-cheatsheets/blob/master/languages/bash.sh\n\n**Content:**\n- Comprehensive syntax guide\n- Examples and explanations\n- Best practices\n\n**Use for:** Single-file reference\n\n### explainshell.com\n\n**URL:** https://explainshell.com/\n\n**Description:** Interactive tool that explains shell commands\n\n**Example:** Paste `tar -xzvf file.tar.gz` to get detailed explanation of each flag\n\n**Use for:** Understanding complex commands, learning command options\n\n### Command Line Fu\n\n**URL:** https://www.commandlinefu.com/\n\n**Description:** Community-contributed command-line snippets\n\n**Use for:** One-liners, clever solutions, learning new commands\n\n### tldr Pages\n\n**URL:** https://tldr.sh/\n**GitHub:** https://github.com/tldr-pages/tldr\n\n**Description:** Simplified man pages with examples\n\n**Installation:**\n```bash\nnpm install -g tldr\n# Or\nbrew install tldr\n```\n\n**Usage:**\n```bash\ntldr tar\ntldr grep\ntldr find\n```\n\n**Use for:** Quick command examples, practical usage\n\n---\n\n## Testing and Quality\n\n### Testing Frameworks\n\n**BATS (Bash Automated Testing System)**\n- **URL:** https://github.com/bats-core/bats-core\n- **Documentation:** https://bats-core.readthedocs.io/\n- **Use for:** Unit testing\n\n**shUnit2**\n- **URL:** https://github.com/kward/shunit2\n- **Description:** xUnit-based unit testing framework\n- **Use for:** Alternative to BATS\n\n**Bash Unit**\n- **URL:** https://github.com/pgrange/bash_unit\n- **Description:** Bash unit testing\n- **Use for:** Lightweight testing\n\n### CI/CD Integration\n\n**GitHub Actions Example**\n```yaml\nname: Test\non: [push, pull_request]\njobs:\n test:\n runs-on: ubuntu-latest\n steps:\n - uses: actions/checkout@v3\n - name: Install ShellCheck\n run: sudo apt-get install -y shellcheck\n - name: Run ShellCheck\n run: find . -name \"*.sh\" -exec shellcheck {} +\n - name: Install BATS\n run: |\n git clone https://github.com/bats-core/bats-core.git\n cd bats-core\n sudo ./install.sh /usr/local\n - name: Run Tests\n run: bats test/\n```\n\n**GitLab CI Example**\n```yaml\ntest:\n image: koalaman/shellcheck-alpine\n script:\n - find . -name \"*.sh\" -exec shellcheck {} +\n\nbats:\n image: bats/bats\n script:\n - bats test/\n```\n\n### Code Coverage\n\n**bashcov**\n- **URL:** https://github.com/infertux/bashcov\n- **Description:** Code coverage for bash\n- **Installation:** `gem install bashcov`\n- **Use for:** Measuring test coverage\n\n---\n\n## Platform-Specific Resources\n\n### Linux\n\n**Linux Man Pages**\n- **URL:** https://man7.org/linux/man-pages/\n- **Use for:** Linux-specific command documentation\n\n**systemd Documentation**\n- **URL:** https://www.freedesktop.org/software/systemd/man/\n- **Use for:** systemd service management\n\n### macOS\n\n**macOS Man Pages**\n- **URL:** https://www.freebsd.org/cgi/man.cgi\n- **Description:** BSD-based commands (similar to macOS)\n- **Use for:** macOS command differences\n\n**Homebrew**\n- **URL:** https://brew.sh/\n- **Use for:** Installing GNU tools on macOS\n\n### Windows\n\n**Git for Windows**\n- **URL:** https://gitforwindows.org/\n- **Documentation:** https://github.com/git-for-windows/git/wiki\n- **Use for:** Git Bash on Windows\n\n**WSL Documentation**\n- **URL:** https://docs.microsoft.com/en-us/windows/wsl/\n- **Use for:** Windows Subsystem for Linux\n\n**Cygwin**\n- **URL:** https://www.cygwin.com/\n- **Use for:** POSIX environment on Windows\n\n### Containers\n\n**Docker Bash Best Practices**\n- **URL:** https://docs.docker.com/develop/develop-images/dockerfile_best-practices/\n- **Use for:** Bash in containers\n\n**Container Best Practices**\n- **URL:** https://cloud.google.com/architecture/best-practices-for-building-containers\n- **Use for:** Production container scripts\n\n---\n\n## Advanced Topics\n\n### Process Substitution\n\n**Greg's Wiki:**\n- **URL:** https://mywiki.wooledge.org/ProcessSubstitution\n- **Use for:** Understanding `\u003c()` syntax\n\n### Parameter Expansion\n\n**Bash Hackers Wiki:**\n- **URL:** https://wiki.bash-hackers.org/syntax/pe\n- **Use for:** Complete parameter expansion reference\n\n### Regular Expressions\n\n**Bash Regex:**\n- **URL:** https://mywiki.wooledge.org/RegularExpression\n- **Use for:** Regex in bash `[[ =~ ]]`\n\n**PCRE vs POSIX:**\n- **URL:** https://www.regular-expressions.info/posix.html\n- **Use for:** Understanding regex flavors\n\n### Parallel Processing\n\n**GNU Parallel:**\n- **URL:** https://www.gnu.org/software/parallel/\n- **Tutorial:** https://www.gnu.org/software/parallel/parallel_tutorial.html\n- **Use for:** Parallel command execution\n\n### Job Control\n\n**Bash Job Control:**\n- **URL:** https://www.gnu.org/software/bash/manual/html_node/Job-Control.html\n- **Use for:** Background jobs, job management\n\n---\n\n## Troubleshooting Resources\n\n### Debugging Tools\n\n**bashdb**\n- **URL:** http://bashdb.sourceforge.net/\n- **Description:** Bash debugger\n- **Use for:** Step-by-step debugging\n\n**xtrace**\n```bash\nset -x # Enable\nset +x # Disable\n```\n- **Use for:** Trace command execution\n\n**PS4 for Better Trace Output**\n```bash\nexport PS4='+(${BASH_SOURCE}:${LINENO}): ${FUNCNAME[0]:+${FUNCNAME[0]}(): }'\nset -x\n```\n\n### Common Issues\n\n**Bash Pitfalls**\n- **URL:** https://mywiki.wooledge.org/BashPitfalls\n- **Description:** 50+ common mistakes in bash\n- **Use for:** Avoiding and fixing common errors\n\n**Bash FAQ**\n- **URL:** https://mywiki.wooledge.org/BashFAQ\n- **Description:** Frequently asked questions\n- **Use for:** Quick answers to common questions\n\n---\n\n## Summary: Where to Find Information\n\n| Question Type | Resource |\n|---------------|----------|\n| Syntax reference | Bash Manual, DevHints cheat sheet |\n| Best practices | Google Shell Style Guide, ShellCheck |\n| Portable scripting | POSIX specification, checkbashisms |\n| Quick examples | tldr, explainshell.com |\n| Common mistakes | Bash Pitfalls, ShellCheck Wiki |\n| Advanced topics | Bash Hackers Wiki, Greg's Wiki |\n| Testing | BATS documentation |\n| Platform differences | Platform-specific docs, Stack Overflow |\n| Troubleshooting | Stack Overflow, Unix & Linux SE |\n| Learning path | Bash Academy, TLDP guides |\n\n---\n\n## Quick Resource Lookup\n\n**When writing a new script:**\n1. Start with template from Google Style Guide\n2. Use ShellCheck while developing\n3. Reference Bash Manual for specific features\n4. Check Bash Pitfalls for common mistakes\n\n**When debugging:**\n1. Use `set -x` for tracing\n2. Check ShellCheck warnings\n3. Search Bash Pitfalls\n4. Search Stack Overflow for specific error\n\n**When learning:**\n1. Start with Bash Academy or TLDP\n2. Use explainshell.com for commands\n3. Read Greg's Wiki for in-depth topics\n4. Practice with BATS tests\n\n**When ensuring quality:**\n1. Run ShellCheck\n2. Run shellcheck\n3. Format with shfmt\n4. Write BATS tests\n5. Review against Google Style Guide\n\nThese resources provide authoritative, up-to-date information for all aspects of bash scripting.\n","content_type":"text/markdown; charset=utf-8","language":"markdown","size":18739,"content_sha256":"1f5844996294b71fd25ca579bbe66f307b2799e8369a48b2f310096baece6bb8"},{"filename":"references/windows-git-bash-paths.md","content":"# Windows Git Bash / MINGW Path Conversion & Shell Detection\n\n**CRITICAL KNOWLEDGE FOR BASH SCRIPTING ON WINDOWS**\n\nThis reference provides comprehensive guidance for handling path conversion and shell detection in Git Bash/MINGW/MSYS2 environments on Windows - essential knowledge for cross-platform bash scripting.\n\n---\n\n## Table of Contents\n\n1. [Path Conversion in Git Bash/MINGW](#path-conversion-in-git-bashMINGW)\n2. [Shell Detection Methods](#shell-detection-methods)\n3. [Claude Code Specific Issues](#claude-code-specific-issues)\n4. [Practical Solutions](#practical-solutions)\n5. [Best Practices](#best-practices)\n\n---\n\n## Path Conversion in Git Bash/MINGW\n\n### Automatic Conversion Behavior\n\nGit Bash/MINGW automatically converts Unix-style paths to Windows paths when passing arguments to native Windows programs. Understanding this behavior is critical for writing portable scripts.\n\n**Conversion Rules:**\n\n```bash\n# Unix → Windows path conversion\n/foo → C:/Program Files/Git/usr/foo\n\n# Path lists (colon-separated → semicolon-separated)\n/foo:/bar → C:\\msys64\\foo;C:\\msys64\\bar\n\n# Arguments with paths\n--dir=/foo → --dir=C:/msys64/foo\n```\n\n### What Triggers Conversion\n\nAutomatic path conversion is triggered by:\n\n```bash\n# ✓ Leading forward slash (/) in arguments\ncommand /c/Users/username/file.txt\n\n# ✓ Colon-separated path lists\nexport PATH=/usr/bin:/usr/local/bin\n\n# ✓ Arguments after - or , with path components\ncommand --path=/tmp/data\n```\n\n### What's Exempt from Conversion\n\nThese patterns do NOT trigger automatic conversion:\n\n```bash\n# ✓ Arguments containing = (variable assignments)\nVAR=/path/to/something\n\n# ✓ Drive specifiers (C:)\nC:/Windows/System32\n\n# ✓ Arguments with ; (already Windows format)\nPATH=C:\\foo;C:\\bar\n\n# ✓ Arguments starting with // (Windows switches or UNC paths)\n//server/share\ncommand //e //s # Command-line switches\n```\n\n### Control Environment Variables\n\n**MSYS_NO_PATHCONV** (Git for Windows only):\n\n```bash\n# Disable ALL path conversion\nexport MSYS_NO_PATHCONV=1\ncommand /path/to/file\n\n# Per-command usage (recommended)\nMSYS_NO_PATHCONV=1 command /path/to/file\n\n# Value doesn't matter, just needs to be defined\nMSYS_NO_PATHCONV=0 # Still disables conversion\n```\n\n**MSYS2_ARG_CONV_EXCL** (MSYS2 only):\n\n```bash\n# Exclude everything\nexport MSYS2_ARG_CONV_EXCL=\"*\"\n\n# Exclude specific prefixes\nexport MSYS2_ARG_CONV_EXCL=\"--dir=;/test\"\n\n# Multiple patterns (semicolon-separated)\nexport MSYS2_ARG_CONV_EXCL=\"--path=;--config=;/tmp\"\n```\n\n**MSYS2_ENV_CONV_EXCL**:\n\n```bash\n# Prevents environment variable conversion\n# Same syntax as MSYS2_ARG_CONV_EXCL\nexport MSYS2_ENV_CONV_EXCL=\"MY_PATH;CONFIG_DIR\"\n```\n\n### Manual Conversion with cygpath\n\nThe `cygpath` utility provides precise control over path conversion:\n\n```bash\n# Convert Windows → Unix format\nunix_path=$(cygpath -u \"C:\\Users\\username\\file.txt\")\n# Result: /c/Users/username/file.txt\n\n# Convert Unix → Windows format\nwindows_path=$(cygpath -w \"/c/Users/username/file.txt\")\n# Result: C:\\Users\\username\\file.txt\n\n# Convert to mixed format (forward slashes, Windows drive)\nmixed_path=$(cygpath -m \"/c/Users/username/file.txt\")\n# Result: C:/Users/username/file.txt\n\n# Convert absolute path\nabsolute_path=$(cygpath -a \"relative/path\")\n\n# Convert multiple paths\ncygpath -u \"C:\\path1\" \"C:\\path2\"\n```\n\n**Practical cygpath usage:**\n\n```bash\n#!/usr/bin/env bash\n# Cross-platform path handling\n\nget_native_path() {\n local path=\"$1\"\n\n # Check if running on Windows (Git Bash/MINGW)\n if [[ \"$OSTYPE\" == \"msys\" ]] || [[ \"$OSTYPE\" == \"mingw\"* ]]; then\n # Convert to Windows format for native programs\n cygpath -w \"$path\"\n else\n # Already Unix format on Linux/macOS\n echo \"$path\"\n fi\n}\n\n# Usage\nnative_path=$(get_native_path \"/c/Users/data\")\nwindows_program.exe \"$native_path\"\n```\n\n### Common Workarounds\n\nWhen automatic conversion causes issues:\n\n**1. Use double slashes:**\n\n```bash\n# Problem: /e gets converted to C:/Program Files/Git/e\ncommand /e /s\n\n# Solution: Use double slashes\ncommand //e //s # Treated as switches, not paths\n```\n\n**2. Use dash notation:**\n\n```bash\n# Problem: /e flag converted to path\ncommand /e /s\n\n# Solution: Use dash notation\ncommand -e -s\n```\n\n**3. Set MSYS_NO_PATHCONV temporarily:**\n\n```bash\n# Disable conversion for single command\nMSYS_NO_PATHCONV=1 command /path/with/special/chars\n\n# Or export for script section\nexport MSYS_NO_PATHCONV=1\ncommand1 /path1\ncommand2 /path2\nunset MSYS_NO_PATHCONV\n```\n\n**4. Quote paths with spaces:**\n\n```bash\n# Always quote paths with spaces\ncommand \"/c/Program Files/App/file.txt\"\n\n# Or escape spaces\ncommand /c/Program\\ Files/App/file.txt\n```\n\n---\n\n## Shell Detection Methods\n\n### Method 1: $OSTYPE (Fastest, Bash-Only)\n\nBest for: Quick platform detection in bash scripts\n\n```bash\n#!/usr/bin/env bash\n\ncase \"$OSTYPE\" in\n linux-gnu*)\n echo \"Linux\"\n ;;\n darwin*)\n echo \"macOS\"\n ;;\n cygwin*)\n echo \"Cygwin\"\n ;;\n msys*)\n echo \"MSYS/Git Bash/MinGW\"\n # Most common in Git for Windows\n ;;\n win*)\n echo \"Windows (native)\"\n ;;\n *)\n echo \"Unknown: $OSTYPE\"\n ;;\nesac\n```\n\n**Advantages:**\n- Fast (shell variable, no external command)\n- Reliable for bash\n- No forking required\n\n**Disadvantages:**\n- Bash-specific (not available in POSIX sh)\n- Less detailed than uname\n\n### Method 2: uname -s (Most Portable)\n\nBest for: Maximum portability and detailed information\n\n```bash\n#!/bin/sh\n# Works in any POSIX shell\n\ncase \"$(uname -s)\" in\n Darwin*)\n echo \"macOS\"\n ;;\n Linux*)\n # Check for WSL\n if grep -qi microsoft /proc/version 2>/dev/null; then\n echo \"Windows Subsystem for Linux (WSL)\"\n else\n echo \"Linux (native)\"\n fi\n ;;\n CYGWIN*)\n echo \"Cygwin\"\n ;;\n MINGW64*)\n echo \"Git Bash 64-bit / MINGW64\"\n ;;\n MINGW32*)\n echo \"Git Bash 32-bit / MINGW32\"\n ;;\n MSYS_NT*)\n echo \"MSYS\"\n ;;\n *)\n echo \"Unknown: $(uname -s)\"\n ;;\nesac\n```\n\n**Common uname -s outputs:**\n\n| Output | Platform | Description |\n|--------|----------|-------------|\n| `Darwin` | macOS | All macOS versions |\n| `Linux` | Linux/WSL | Check `/proc/version` for WSL |\n| `MINGW64_NT-10.0-*` | Git Bash | Git for Windows (64-bit) |\n| `MINGW32_NT-10.0-*` | Git Bash | Git for Windows (32-bit) |\n| `CYGWIN_NT-*` | Cygwin | Cygwin environment |\n| `MSYS_NT-*` | MSYS | MSYS environment |\n\n**Advantages:**\n- Works in any POSIX shell\n- Detailed system information\n- Standard on all Unix-like systems\n\n**Disadvantages:**\n- Requires forking (slower than $OSTYPE)\n- Output format varies by OS version\n\n### Method 3: $MSYSTEM (MSYS2/Git Bash Specific)\n\nBest for: Detecting MINGW subsystem type\n\n```bash\n#!/usr/bin/env bash\n\ncase \"$MSYSTEM\" in\n MINGW64)\n echo \"Native Windows 64-bit environment\"\n # Build native Windows 64-bit applications\n ;;\n MINGW32)\n echo \"Native Windows 32-bit environment\"\n # Build native Windows 32-bit applications\n ;;\n MSYS)\n echo \"POSIX-compliant environment\"\n # Build POSIX applications (depend on msys-2.0.dll)\n ;;\n \"\")\n echo \"Not running in MSYS2/Git Bash\"\n ;;\n *)\n echo \"Unknown MSYSTEM: $MSYSTEM\"\n ;;\nesac\n```\n\n**MSYSTEM Values:**\n\n| Value | Purpose | Path Conversion | Libraries |\n|-------|---------|-----------------|-----------|\n| `MINGW64` | Native Windows 64-bit | Automatic | Windows native (mingw-w64) |\n| `MINGW32` | Native Windows 32-bit | Automatic | Windows native (mingw) |\n| `MSYS` | POSIX environment | Minimal | POSIX (msys-2.0.dll) |\n\n**WARNING:** Never set `$MSYSTEM` manually outside of MSYS2/Git Bash shells! It's automatically set by the environment and changing it can break the system.\n\n**Advantages:**\n- Precise subsystem detection\n- Important for build systems\n- Fast (environment variable)\n\n**Disadvantages:**\n- Only available in MSYS2/Git Bash\n- Not set on other platforms\n\n### Comprehensive Detection Function\n\nCombine all methods for robust detection:\n\n```bash\n#!/usr/bin/env bash\n\ndetect_platform() {\n local platform=\"\"\n local details=\"\"\n\n # Check MSYSTEM first (most specific for Git Bash)\n if [[ -n \"${MSYSTEM:-}\" ]]; then\n platform=\"gitbash\"\n details=\"$MSYSTEM\"\n echo \"platform=$platform subsystem=$MSYSTEM\"\n return 0\n fi\n\n # Check OSTYPE\n case \"$OSTYPE\" in\n linux-gnu*)\n # Distinguish WSL from native Linux\n if grep -qi microsoft /proc/version 2>/dev/null; then\n platform=\"wsl\"\n if [[ -n \"${WSL_DISTRO_NAME:-}\" ]]; then\n details=\"$WSL_DISTRO_NAME\"\n fi\n else\n platform=\"linux\"\n fi\n ;;\n darwin*)\n platform=\"macos\"\n ;;\n msys*|mingw*|cygwin*)\n platform=\"gitbash\"\n ;;\n *)\n # Fallback to uname\n case \"$(uname -s 2>/dev/null)\" in\n MINGW*|MSYS*)\n platform=\"gitbash\"\n ;;\n CYGWIN*)\n platform=\"cygwin\"\n ;;\n *)\n platform=\"unknown\"\n ;;\n esac\n ;;\n esac\n\n echo \"platform=$platform${details:+ details=$details}\"\n}\n\n# Usage\nplatform_info=$(detect_platform)\necho \"$platform_info\"\n```\n\n---\n\n## Claude Code Specific Issues\n\n### Issue #2602: Snapshot Path Conversion Failure\n\n**Problem:**\n```text\n/usr/bin/bash: line 1: C:UsersDavid...No such file\n```\n\n**Root Cause:**\n- Node.js `os.tmpdir()` returns Windows paths (e.g., `C:\\Users\\...`)\n- Git Bash expects Unix paths (e.g., `/c/Users/...`)\n- Automatic conversion fails due to path format mismatch\n\n**Solution (Claude Code v1.0.51+):**\n\nSet environment variable before starting Claude Code:\n\n```powershell\n# PowerShell\n$env:CLAUDE_CODE_GIT_BASH_PATH = \"C:\\Program Files\\git\\bin\\bash.exe\"\n```\n\n```cmd\n# CMD\nset CLAUDE_CODE_GIT_BASH_PATH=C:\\Program Files\\git\\bin\\bash.exe\n```\n\n```bash\n# Git Bash (add to ~/.bashrc)\nexport CLAUDE_CODE_GIT_BASH_PATH=\"C:\\\\Program Files\\\\git\\\\bin\\\\bash.exe\"\n```\n\n**Note:** Versions 1.0.72+ reportedly work without modifications, but setting the environment variable ensures compatibility.\n\n### Other Known Issues\n\n**Drive letter duplication:**\n```bash\n# Problem\ncd D:\\dev\npwd\n# Output: D:\\d\\dev (incorrect)\n\n# Solution: Use Unix-style path in Git Bash\ncd /d/dev\npwd\n# Output: /d/dev\n```\n\n**Spaces in paths:**\n```bash\n# Problem: Unquoted path with spaces\ncd C:\\Program Files\\App # Fails\n\n# Solution: Always quote paths with spaces\ncd \"C:\\Program Files\\App\"\ncd /c/Program\\ Files/App\n```\n\n**VS Code extension Git Bash detection:**\n\nVS Code may not auto-detect Git Bash. Configure manually in settings:\n\n```json\n{\n \"terminal.integrated.defaultProfile.windows\": \"Git Bash\",\n \"terminal.integrated.profiles.windows\": {\n \"Git Bash\": {\n \"path\": \"C:\\\\Program Files\\\\Git\\\\bin\\\\bash.exe\"\n }\n }\n}\n```\n\n---\n\n## Practical Solutions\n\n### Cross-Platform Path Handling Function\n\n```bash\n#!/usr/bin/env bash\n\n# Convert path to format appropriate for current platform\nnormalize_path_for_platform() {\n local path=\"$1\"\n\n case \"$OSTYPE\" in\n msys*|mingw*)\n # On Git Bash, convert to Unix format if Windows format provided\n if [[ \"$path\" =~ ^[A-Z]:\\\\ ]]; then\n # Windows path detected, convert to Unix\n path=$(cygpath -u \"$path\" 2>/dev/null || echo \"$path\")\n fi\n ;;\n *)\n # On Linux/macOS, path is already correct\n ;;\n esac\n\n echo \"$path\"\n}\n\n# Convert path to native format for external programs\nconvert_to_native_path() {\n local path=\"$1\"\n\n case \"$OSTYPE\" in\n msys*|mingw*)\n # Convert to Windows format for native Windows programs\n cygpath -w \"$path\" 2>/dev/null || echo \"$path\"\n ;;\n *)\n # Already native on Linux/macOS\n echo \"$path\"\n ;;\n esac\n}\n\n# Example usage\ninput_path=\"/c/Users/username/file.txt\"\nnormalized=$(normalize_path_for_platform \"$input_path\")\necho \"Normalized: $normalized\"\n\nnative=$(convert_to_native_path \"$normalized\")\necho \"Native: $native\"\n```\n\n### Script Template for Windows Compatibility\n\n```bash\n#!/usr/bin/env bash\nset -euo pipefail\n\n# Detect if running on Git Bash/MINGW\nis_git_bash() {\n [[ \"$OSTYPE\" == \"msys\" ]] || [[ \"$OSTYPE\" == \"mingw\"* ]]\n}\n\n# Handle path conversion based on platform\nget_path() {\n local path=\"$1\"\n\n if is_git_bash; then\n # Ensure Unix format in Git Bash\n if [[ \"$path\" =~ ^[A-Z]:\\\\ ]]; then\n cygpath -u \"$path\"\n else\n echo \"$path\"\n fi\n else\n echo \"$path\"\n fi\n}\n\n# Call Windows program from Git Bash\ncall_windows_program() {\n local program=\"$1\"\n shift\n local args=(\"$@\")\n\n if is_git_bash; then\n # Disable path conversion for complex arguments\n MSYS_NO_PATHCONV=1 \"$program\" \"${args[@]}\"\n else\n \"$program\" \"${args[@]}\"\n fi\n}\n\n# Main script logic\nmain() {\n local file_path=\"$1\"\n\n # Normalize path\n file_path=$(get_path \"$file_path\")\n\n # Process file\n echo \"Processing: $file_path\"\n\n # Call Windows program if needed\n if is_git_bash; then\n local native_path\n native_path=$(cygpath -w \"$file_path\")\n call_windows_program notepad.exe \"$native_path\"\n fi\n}\n\nmain \"$@\"\n```\n\n### Handling Command-Line Arguments\n\n```bash\n#!/usr/bin/env bash\n\n# Parse arguments that might contain paths\nparse_arguments() {\n while [[ $# -gt 0 ]]; do\n case \"$1\" in\n --path=*)\n local path=\"${1#*=}\"\n # Disable conversion for this specific argument pattern\n MSYS2_ARG_CONV_EXCL=\"--path=\" command --path=\"$path\"\n shift\n ;;\n --dir)\n local dir=\"$2\"\n # Use converted path\n local native_dir\n if command -v cygpath &>/dev/null; then\n native_dir=$(cygpath -w \"$dir\")\n else\n native_dir=\"$dir\"\n fi\n command --dir \"$native_dir\"\n shift 2\n ;;\n *)\n shift\n ;;\n esac\n done\n}\n```\n\n---\n\n## Best Practices\n\n### 1. Always Quote Paths\n\n```bash\n# ✗ WRONG - Breaks with spaces\ncd $path\n\n# ✓ CORRECT - Works with all paths\ncd \"$path\"\n```\n\n### 2. Use cygpath for Reliable Conversion\n\n```bash\n# ✗ WRONG - Manual conversion is error-prone\npath=\"${path//\\\\/\\/}\"\npath=\"${path/C:/\\/c}\"\n\n# ✓ CORRECT - Use cygpath\npath=$(cygpath -u \"$path\")\n```\n\n### 3. Detect Platform Before Path Operations\n\n```bash\n# ✓ CORRECT - Platform-aware\nif [[ \"$OSTYPE\" == \"msys\" ]] || [[ \"$OSTYPE\" == \"mingw\"* ]]; then\n # Git Bash specific handling\n path=$(cygpath -u \"$windows_path\")\nelse\n # Linux/macOS handling\n path=\"$unix_path\"\nfi\n```\n\n### 4. Use MSYS_NO_PATHCONV Sparingly\n\n```bash\n# ✗ WRONG - Disables all conversion globally\nexport MSYS_NO_PATHCONV=1\n\n# ✓ CORRECT - Per-command when needed\nMSYS_NO_PATHCONV=1 command --flag=/value\n```\n\n### 5. Test on Target Platform\n\nAlways test scripts on Windows with Git Bash if that's a target platform:\n\n```bash\n# Test script\nbash -n script.sh # Syntax check\nshellcheck script.sh # Static analysis\nbash script.sh # Run on actual platform\n```\n\n### 6. Document Platform Requirements\n\n```bash\n#!/usr/bin/env bash\n#\n# Platform Support:\n# - Linux: Full support\n# - macOS: Full support\n# - Windows Git Bash: Requires Git for Windows 2.x+\n# - Windows WSL: Full support\n#\n# Known Issues:\n# - Path conversion may occur when calling Windows programs from Git Bash\n# - Use MSYS_NO_PATHCONV=1 if experiencing path-related errors\n```\n\n### 7. Use Forward Slashes in Git Bash\n\n```bash\n# ✓ PREFERRED - Works in all environments\ncd /c/Users/username/project\n\n# ✗ AVOID - Requires escaping or quoting\ncd \"C:\\Users\\username\\project\"\ncd C:\\\\Users\\\\username\\\\project\n```\n\n### 8. Check for cygpath Availability\n\n```bash\n# Graceful fallback if cygpath not available\nconvert_path() {\n local path=\"$1\"\n\n if command -v cygpath &>/dev/null; then\n cygpath -u \"$path\"\n else\n # Manual conversion as fallback\n echo \"$path\" | sed 's|\\\\|/|g' | sed 's|^\\([A-Z]\\):|/\\L\\1|'\n fi\n}\n```\n\n---\n\n## Quick Reference Card\n\n### Path Conversion Control\n\n| Variable | Scope | Effect |\n|----------|-------|--------|\n| `MSYS_NO_PATHCONV=1` | Git for Windows | Disables all conversion |\n| `MSYS2_ARG_CONV_EXCL=\"pattern\"` | MSYS2 | Excludes specific patterns |\n| `MSYS2_ENV_CONV_EXCL=\"var\"` | MSYS2 | Excludes environment variables |\n\n### Shell Detection Variables\n\n| Variable | Available | Purpose |\n|----------|-----------|---------|\n| `$OSTYPE` | Bash | Quick OS type detection |\n| `$MSYSTEM` | MSYS2/Git Bash | Subsystem type (MINGW64/MINGW32/MSYS) |\n| `$(uname -s)` | All POSIX | Detailed OS identification |\n\n### cygpath Quick Reference\n\n| Command | Purpose |\n|---------|---------|\n| `cygpath -u \"C:\\path\"` | Windows → Unix format |\n| `cygpath -w \"/c/path\"` | Unix → Windows format |\n| `cygpath -m \"/c/path\"` | Unix → Mixed format (forward slashes) |\n| `cygpath -a \"path\"` | Convert to absolute path |\n\n### Common Issues & Solutions\n\n| Problem | Solution |\n|---------|----------|\n| Path with spaces breaks | Quote the path: `\"$path\"` |\n| Flag `/e` converted to path | Use `//e` or `-e` instead |\n| Drive duplication `D:\\d\\` | Use Unix format: `/d/` |\n| Windows program needs Windows path | Use `cygpath -w \"$unix_path\"` |\n| Script fails in Claude Code | Set `CLAUDE_CODE_GIT_BASH_PATH` |\n\n---\n\n## Summary\n\nUnderstanding Git Bash/MINGW path conversion is essential for writing robust cross-platform bash scripts that work on Windows. Key takeaways:\n\n1. **Automatic conversion** happens for Unix-style paths in arguments\n2. **Control conversion** using `MSYS_NO_PATHCONV` and `MSYS2_ARG_CONV_EXCL`\n3. **Use cygpath** for reliable manual path conversion\n4. **Detect platform** using `$OSTYPE`, `$MSYSTEM`, or `uname -s`\n5. **Quote all paths** to handle spaces and special characters\n6. **Test on target platforms** to catch platform-specific issues\n7. **Document requirements** so users know what to expect\n\nWith this knowledge, you can write bash scripts that work seamlessly across Linux, macOS, Windows Git Bash, WSL, and other Unix-like environments.\n","content_type":"text/markdown; charset=utf-8","language":"markdown","size":18608,"content_sha256":"048869b039c3157359853d3cc919b069a81ad23693015a7fe082ebde385c4766"}],"content_json":{"type":"doc","content":[{"type":"heading","attrs":{"level":1},"content":[{"text":"Bash Scripting Mastery","type":"text"}]},{"type":"heading","attrs":{"level":2},"content":[{"text":"Scope and platform contract","type":"text"}]},{"type":"paragraph","content":[{"text":"This skill targets ","type":"text"},{"text":"Bash itself","type":"text","marks":[{"type":"strong"}]},{"text":", wherever Bash runs - Linux, macOS, WSL, Git Bash / MSYS2 on Windows, and Bash-based container images. It does not cover ","type":"text"},{"text":"native PowerShell","type":"text","marks":[{"type":"strong"}]},{"text":": a PowerShell script is a different language and should use ","type":"text"},{"text":"powershell-master","type":"text","marks":[{"type":"code_inline"}]},{"text":". On Windows, ","type":"text"},{"text":"bash-master","type":"text","marks":[{"type":"code_inline"}]},{"text":" assumes the user is running Bash inside Git Bash, WSL, or a similar Bash environment, and addresses the MSYS path-translation quirks that result.","type":"text"}]},{"type":"heading","attrs":{"level":2},"content":[{"text":"Repository conventions","type":"text"}]},{"type":"paragraph","content":[{"text":"Project-level conventions (Windows backslashes in tool calls, documentation discipline, etc.) live in the agent body and the ","type":"text"},{"text":"windows-path-master","type":"text","marks":[{"type":"code_inline"}]},{"text":" plugin. This skill focuses on Bash content; do not duplicate that boilerplate here.","type":"text"}]},{"type":"heading","attrs":{"level":2},"content":[{"text":"Quick reference","type":"text"}]},{"type":"code_block","attrs":{"wrap":false,"language":"bash"},"content":[{"text":"#!/usr/bin/env bash\nset -euo pipefail # Exit on error, undefined vars, pipe failures\nIFS=

Bash Scripting Mastery Scope and platform contract This skill targets Bash itself , wherever Bash runs - Linux, macOS, WSL, Git Bash / MSYS2 on Windows, and Bash-based container images. It does not cover native PowerShell : a PowerShell script is a different language and should use . On Windows, assumes the user is running Bash inside Git Bash, WSL, or a similar Bash environment, and addresses the MSYS path-translation quirks that result. Repository conventions Project-level conventions (Windows backslashes in tool calls, documentation discipline, etc.) live in the agent body and the plugin.…

\\n\\t' # Safe word splitting\n# Run shellcheck your_script.sh before deployment.\n# Test on every target platform before production.","type":"text"}]},{"type":"paragraph","content":[{"text":"Bash-portability quick check:","type":"text","marks":[{"type":"strong"}]}]},{"type":"code_block","attrs":{"wrap":false,"language":"bash"},"content":[{"text":"# Linux/macOS: Full bash features\n# Git Bash (Windows): Most features, some system calls missing (no systemd, /proc differs)\n# WSL: Effectively Linux; /mnt/c for Windows filesystem\n# Containers: Depends on base image - alpine ships /bin/sh, not bash\n# POSIX mode: Use /bin/sh and avoid bashisms","type":"text"}]},{"type":"heading","attrs":{"level":2},"content":[{"text":"When to use this skill","type":"text"}]},{"type":"paragraph","content":[{"text":"Always activate for:","type":"text","marks":[{"type":"strong"}]}]},{"type":"bullet_list","content":[{"type":"list_item","content":[{"type":"paragraph","content":[{"text":"Writing or modifying any bash/shell script","type":"text"}]}]},{"type":"list_item","content":[{"type":"paragraph","content":[{"text":"Reviewing or refactoring existing scripts","type":"text"}]}]},{"type":"list_item","content":[{"type":"paragraph","content":[{"text":"Debugging shell script failures","type":"text"}]}]},{"type":"list_item","content":[{"type":"paragraph","content":[{"text":"DevOps automation, CI/CD pipelines, system administration","type":"text"}]}]},{"type":"list_item","content":[{"type":"paragraph","content":[{"text":"Cross-environment Bash portability (Linux \u003c-> macOS \u003c-> WSL \u003c-> Git Bash \u003c-> container)","type":"text"}]}]}]},{"type":"paragraph","content":[{"text":"Do not use this skill for:","type":"text","marks":[{"type":"strong"}]}]},{"type":"bullet_list","content":[{"type":"list_item","content":[{"type":"paragraph","content":[{"text":"PowerShell scripts - use ","type":"text"},{"text":"powershell-master","type":"text","marks":[{"type":"code_inline"}]}]}]},{"type":"list_item","content":[{"type":"paragraph","content":[{"text":"Batch (","type":"text"},{"text":".cmd","type":"text","marks":[{"type":"code_inline"}]},{"text":"/","type":"text"},{"text":".bat","type":"text","marks":[{"type":"code_inline"}]},{"text":") scripting","type":"text"}]}]},{"type":"list_item","content":[{"type":"paragraph","content":[{"text":"Generic command help unrelated to scripting","type":"text"}]}]}]},{"type":"heading","attrs":{"level":2},"content":[{"text":"Core principles","type":"text"}]},{"type":"heading","attrs":{"level":3},"content":[{"text":"1. Safety first","type":"text"}]},{"type":"paragraph","content":[{"text":"Every script should open with the safety preamble:","type":"text"}]},{"type":"code_block","attrs":{"wrap":false,"language":"bash"},"content":[{"text":"#!/usr/bin/env bash\nset -e # Exit on any error\nset -u # Exit on undefined variable\nset -o pipefail # Catch failures mid-pipeline\nset -E # Inherit ERR trap into functions\nIFS=

Bash Scripting Mastery Scope and platform contract This skill targets Bash itself , wherever Bash runs - Linux, macOS, WSL, Git Bash / MSYS2 on Windows, and Bash-based container images. It does not cover native PowerShell : a PowerShell script is a different language and should use . On Windows, assumes the user is running Bash inside Git Bash, WSL, or a similar Bash environment, and addresses the MSYS path-translation quirks that result. Repository conventions Project-level conventions (Windows backslashes in tool calls, documentation discipline, etc.) live in the agent body and the plugin.…

\\n\\t' # Avoid word splitting on spaces\n\nreadonly SCRIPT_DIR=\"$(cd \"$(dirname \"${BASH_SOURCE[0]}\")\" && pwd)\"\nreadonly SCRIPT_NAME=\"$(basename \"${BASH_SOURCE[0]}\")\"","type":"text"}]},{"type":"heading","attrs":{"level":3},"content":[{"text":"2. POSIX vs Bash","type":"text"}]},{"type":"table","attrs":{"layout":null},"content":[{"type":"tr","content":[{"type":"th","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"Need to run on any UNIX ","type":"text"},{"text":"sh","type":"text","marks":[{"type":"code_inline"}]}]}]},{"type":"th","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"#!/bin/sh","type":"text","marks":[{"type":"code_inline"}]},{"text":", no ","type":"text"},{"text":"[[ ]]","type":"text","marks":[{"type":"code_inline"}]},{"text":", no arrays, no process substitution","type":"text"}]}]}]},{"type":"tr","content":[{"type":"td","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"Modern Linux/macOS with Bash","type":"text"}]}]},{"type":"td","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"#!/usr/bin/env bash","type":"text","marks":[{"type":"code_inline"}]},{"text":", prefer ","type":"text"},{"text":"[[ ]]","type":"text","marks":[{"type":"code_inline"}]},{"text":", arrays, regex","type":"text"}]}]}]},{"type":"tr","content":[{"type":"td","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"Alpine/minimal containers","type":"text"}]}]},{"type":"td","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"Either install bash explicitly or write POSIX-compliant ","type":"text"},{"text":"sh","type":"text","marks":[{"type":"code_inline"}]}]}]}]}]},{"type":"heading","attrs":{"level":3},"content":[{"text":"3. Quoting","type":"text"}]},{"type":"code_block","attrs":{"wrap":false,"language":"bash"},"content":[{"text":"# Always quote expansions\nprocess \"$file_path\" # correct\nprocess $file_path # word-splitting bug\n\n# Arrays\nfiles=(\"file 1.txt\" \"file 2.txt\")\nprocess \"${files[@]}\" # each element kept separate\nprocess \"${files[*]}\" # joined as one string - usually wrong","type":"text"}]},{"type":"heading","attrs":{"level":3},"content":[{"text":"4. ShellCheck","type":"text"}]},{"type":"paragraph","content":[{"text":"Run ","type":"text"},{"text":"shellcheck","type":"text","marks":[{"type":"code_inline"}]},{"text":" on every script. Only disable warnings with a justification comment: ","type":"text"},{"text":"# shellcheck disable=SC2086 reason: intentional word splitting","type":"text","marks":[{"type":"code_inline"}]},{"text":".","type":"text"}]},{"type":"paragraph","content":[{"text":"See ","type":"text"},{"text":"references/best_practices.md","type":"text","marks":[{"type":"code_inline"}]},{"text":" for the full quoting/style table and ","type":"text"},{"text":"references/patterns_antipatterns.md","type":"text","marks":[{"type":"code_inline"}]},{"text":" for the common pitfalls.","type":"text"}]},{"type":"heading","attrs":{"level":2},"content":[{"text":"Platform-specific considerations","type":"text"}]},{"type":"heading","attrs":{"level":3},"content":[{"text":"Git Bash / MSYS2 (Windows)","type":"text"}]},{"type":"paragraph","content":[{"text":"Git Bash auto-converts Unix-style arguments to Windows paths. This is the largest single source of cross-platform Bash bugs on Windows.","type":"text"}]},{"type":"code_block","attrs":{"wrap":false,"language":"bash"},"content":[{"text":"# The conversion: /foo becomes C:/Program Files/Git/usr/foo\n# Disable per-command:\nMSYS_NO_PATHCONV=1 command /path/that/should/stay/unix\n\n# Manual conversion\nunix_path=$(cygpath -u \"C:\\Windows\\System32\")\nwin_path=$(cygpath -w \"/c/Users/username\")\n\n# Detect Git Bash\nif [[ \"$OSTYPE\" == \"msys\" ]] || [[ \"$OSTYPE\" == \"mingw\"* ]]; then\n : # Git Bash\nfi\ncase \"${MSYSTEM:-}\" in\n MINGW64|MINGW32|MSYS) : ;; # MSYS2 / Git Bash environment\nesac\n\n# Flags that look like paths\ncommand //e //s # double-slash to suppress conversion\ncommand -e -s # or use dash-options","type":"text"}]},{"type":"paragraph","content":[{"text":"Full Git Bash + Windows path notes live in ","type":"text"},{"text":"references/windows-git-bash-paths.md","type":"text","marks":[{"type":"code_inline"}]},{"text":".","type":"text"}]},{"type":"heading","attrs":{"level":3},"content":[{"text":"Linux","type":"text"}]},{"type":"paragraph","content":[{"text":"GNU coreutils, ","type":"text"},{"text":"/proc","type":"text","marks":[{"type":"code_inline"}]},{"text":", systemd integration. Detect via ","type":"text"},{"text":"[[ \"$OSTYPE\" == \"linux-gnu\"* ]]","type":"text","marks":[{"type":"code_inline"}]},{"text":".","type":"text"}]},{"type":"heading","attrs":{"level":3},"content":[{"text":"macOS","type":"text"}]},{"type":"paragraph","content":[{"text":"BSD utilities behave differently from GNU. Most common gotchas: ","type":"text"},{"text":"sed -i ''","type":"text","marks":[{"type":"code_inline"}]},{"text":" (empty string required), ","type":"text"},{"text":"date","type":"text","marks":[{"type":"code_inline"}]},{"text":" flags differ, ","type":"text"},{"text":"readlink -f","type":"text","marks":[{"type":"code_inline"}]},{"text":" not available on stock macOS.","type":"text"}]},{"type":"code_block","attrs":{"wrap":false,"language":"bash"},"content":[{"text":"if command -v gsed >/dev/null; then SED=gsed; else SED=sed; fi","type":"text"}]},{"type":"heading","attrs":{"level":3},"content":[{"text":"WSL","type":"text"}]},{"type":"paragraph","content":[{"text":"Effectively Linux. The Windows filesystem is mounted at ","type":"text"},{"text":"/mnt/c/","type":"text","marks":[{"type":"code_inline"}]},{"text":". Detect via ","type":"text"},{"text":"grep -qi microsoft /proc/version","type":"text","marks":[{"type":"code_inline"}]},{"text":".","type":"text"}]},{"type":"heading","attrs":{"level":3},"content":[{"text":"Containers","type":"text"}]},{"type":"paragraph","content":[{"text":"Alpine images ship only ","type":"text"},{"text":"/bin/sh","type":"text","marks":[{"type":"code_inline"}]},{"text":" (BusyBox). Write POSIX-compliant scripts or ","type":"text"},{"text":"apk add bash","type":"text","marks":[{"type":"code_inline"}]},{"text":". Container init quirks: PID 1 must reap children and handle signals. Detect via ","type":"text"},{"text":"[ -f /.dockerenv ]","type":"text","marks":[{"type":"code_inline"}]},{"text":" or ","type":"text"},{"text":"[ -n \"$KUBERNETES_SERVICE_HOST\" ]","type":"text","marks":[{"type":"code_inline"}]},{"text":".","type":"text"}]},{"type":"heading","attrs":{"level":3},"content":[{"text":"Portable platform-detection template","type":"text"}]},{"type":"code_block","attrs":{"wrap":false,"language":"bash"},"content":[{"text":"detect_platform() {\n case \"$OSTYPE\" in\n linux-gnu*) echo \"linux\" ;;\n darwin*) echo \"macos\" ;;\n msys*|cygwin*) echo \"windows\" ;;\n *) echo \"unknown\" ;;\n esac\n}","type":"text"}]},{"type":"paragraph","content":[{"text":"Full per-platform tables (BSD-vs-GNU coreutils flags, WSL networking, container init patterns) live in ","type":"text"},{"text":"references/platform_specifics.md","type":"text","marks":[{"type":"code_inline"}]},{"text":".","type":"text"}]},{"type":"heading","attrs":{"level":2},"content":[{"text":"Best practices (summary)","type":"text"}]},{"type":"paragraph","content":[{"text":"The full patterns - function design, error handling, input validation, argument parsing, logging - live in ","type":"text"},{"text":"references/in-depth-patterns.md","type":"text","marks":[{"type":"code_inline"}]},{"text":". The headline rules:","type":"text"}]},{"type":"bullet_list","content":[{"type":"list_item","content":[{"type":"paragraph","content":[{"text":"One concern per function; locals declared first; validate input; return non-zero on error.","type":"text"}]}]},{"type":"list_item","content":[{"type":"paragraph","content":[{"text":"Constants ","type":"text"},{"text":"UPPER_CASE","type":"text","marks":[{"type":"code_inline"}]},{"text":"; locals ","type":"text"},{"text":"lower_case","type":"text","marks":[{"type":"code_inline"}]},{"text":"; mark immutable values ","type":"text"},{"text":"readonly","type":"text","marks":[{"type":"code_inline"}]},{"text":".","type":"text"}]}]},{"type":"list_item","content":[{"type":"paragraph","content":[{"text":"Always check exit codes (","type":"text"},{"text":"if ! cmd","type":"text","marks":[{"type":"code_inline"}]},{"text":", ","type":"text"},{"text":"||","type":"text","marks":[{"type":"code_inline"}]},{"text":", traps, or a central ","type":"text"},{"text":"error_exit","type":"text","marks":[{"type":"code_inline"}]},{"text":" helper).","type":"text"}]}]},{"type":"list_item","content":[{"type":"paragraph","content":[{"text":"Validate every external input - empty, format, length, charset.","type":"text"}]}]},{"type":"list_item","content":[{"type":"paragraph","content":[{"text":"Use ","type":"text"},{"text":"getopts","type":"text","marks":[{"type":"code_inline"}]},{"text":" or a ","type":"text"},{"text":"case","type":"text","marks":[{"type":"code_inline"}]},{"text":"-based argument parser; print usage and exit 1 on bad input.","type":"text"}]}]},{"type":"list_item","content":[{"type":"paragraph","content":[{"text":"Use a leveled logger that writes to stderr.","type":"text"}]}]}]},{"type":"heading","attrs":{"level":2},"content":[{"text":"Security, performance, testing, debugging, advanced patterns","type":"text"}]},{"type":"paragraph","content":[{"text":"These each have dedicated sections in ","type":"text"},{"text":"references/in-depth-patterns.md","type":"text","marks":[{"type":"code_inline"}]},{"text":":","type":"text"}]},{"type":"table","attrs":{"layout":null},"content":[{"type":"tr","content":[{"type":"th","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"Topic","type":"text"}]}]},{"type":"th","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"What it covers","type":"text"}]}]}]},{"type":"tr","content":[{"type":"td","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"Security","type":"text"}]}]},{"type":"td","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"Command-injection prevention, path-traversal guards, privilege management, secure temp files","type":"text"}]}]}]},{"type":"tr","content":[{"type":"td","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"Performance","type":"text"}]}]},{"type":"td","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"Avoiding subshells, bash built-ins vs externals, process substitution, array ops","type":"text"}]}]}]},{"type":"tr","content":[{"type":"td","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"Testing","type":"text"}]}]},{"type":"td","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"BATS unit tests, integration test patterns, CI/CD wiring","type":"text"}]}]}]},{"type":"tr","content":[{"type":"td","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"Debugging","type":"text"}]}]},{"type":"td","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"set -x","type":"text","marks":[{"type":"code_inline"}]},{"text":", ","type":"text"},{"text":"PS4","type":"text","marks":[{"type":"code_inline"}]},{"text":", conditional debug helpers, tracing and profiling","type":"text"}]}]}]},{"type":"tr","content":[{"type":"td","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"Advanced patterns","type":"text"}]}]},{"type":"td","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"Safe config parsing, parallel processing, signal handling, retries with backoff","type":"text"}]}]}]}]},{"type":"paragraph","content":[{"text":"Read that reference any time you need the canonical code template for one of those topics.","type":"text"}]},{"type":"heading","attrs":{"level":2},"content":[{"text":"Reference files","type":"text"}]},{"type":"bullet_list","content":[{"type":"list_item","content":[{"type":"paragraph","content":[{"text":"references/platform_specifics.md","type":"text","marks":[{"type":"link","attrs":{"href":"references/platform_specifics.md","title":null}},{"type":"code_inline"}]},{"text":" - Detailed platform differences and workarounds","type":"text"}]}]},{"type":"list_item","content":[{"type":"paragraph","content":[{"text":"references/best_practices.md","type":"text","marks":[{"type":"link","attrs":{"href":"references/best_practices.md","title":null}},{"type":"code_inline"}]},{"text":" - Comprehensive industry standards and guidelines","type":"text"}]}]},{"type":"list_item","content":[{"type":"paragraph","content":[{"text":"references/patterns_antipatterns.md","type":"text","marks":[{"type":"link","attrs":{"href":"references/patterns_antipatterns.md","title":null}},{"type":"code_inline"}]},{"text":" - Common patterns and pitfalls with solutions","type":"text"}]}]},{"type":"list_item","content":[{"type":"paragraph","content":[{"text":"references/windows-git-bash-paths.md","type":"text","marks":[{"type":"link","attrs":{"href":"references/windows-git-bash-paths.md","title":null}},{"type":"code_inline"}]},{"text":" - Git Bash / MSYS path-translation reference","type":"text"}]}]},{"type":"list_item","content":[{"type":"paragraph","content":[{"text":"references/in-depth-patterns.md","type":"text","marks":[{"type":"link","attrs":{"href":"references/in-depth-patterns.md","title":null}},{"type":"code_inline"}]},{"text":" - Function design, security, performance, testing, debugging, advanced patterns","type":"text"}]}]},{"type":"list_item","content":[{"type":"paragraph","content":[{"text":"references/resources.md","type":"text","marks":[{"type":"link","attrs":{"href":"references/resources.md","title":null}},{"type":"code_inline"}]},{"text":" - Official docs, style guides, tooling, and learning links","type":"text"}]}]}]},{"type":"heading","attrs":{"level":2},"content":[{"text":"Success criteria","type":"text"}]},{"type":"paragraph","content":[{"text":"A Bash script written with this skill should:","type":"text"}]},{"type":"ordered_list","attrs":{"order":1,"listStyle":"number"},"content":[{"type":"list_item","content":[{"type":"paragraph","content":[{"text":"Pass ","type":"text"},{"text":"shellcheck","type":"text","marks":[{"type":"code_inline"}]},{"text":" with no warnings","type":"text"}]}]},{"type":"list_item","content":[{"type":"paragraph","content":[{"text":"Begin with ","type":"text"},{"text":"set -euo pipefail","type":"text","marks":[{"type":"code_inline"}]}]}]},{"type":"list_item","content":[{"type":"paragraph","content":[{"text":"Quote every variable expansion","type":"text"}]}]},{"type":"list_item","content":[{"type":"paragraph","content":[{"text":"Print usage on ","type":"text"},{"text":"-h","type":"text","marks":[{"type":"code_inline"}]},{"text":"/","type":"text"},{"text":"--help","type":"text","marks":[{"type":"code_inline"}]}]}]},{"type":"list_item","content":[{"type":"paragraph","content":[{"text":"Decompose into testable functions","type":"text"}]}]},{"type":"list_item","content":[{"type":"paragraph","content":[{"text":"Handle empty input, missing files, and unexpected arguments","type":"text"}]}]},{"type":"list_item","content":[{"type":"paragraph","content":[{"text":"Run on every target platform (Linux/macOS/WSL/Git Bash/container) where it claims support","type":"text"}]}]},{"type":"list_item","content":[{"type":"paragraph","content":[{"text":"Match the Google Shell Style Guide","type":"text"}]}]},{"type":"list_item","content":[{"type":"paragraph","content":[{"text":"Clean up on exit (","type":"text"},{"text":"trap EXIT","type":"text","marks":[{"type":"code_inline"}]},{"text":")","type":"text"}]}]},{"type":"list_item","content":[{"type":"paragraph","content":[{"text":"Be unit-tested with BATS where logic is non-trivial","type":"text"}]}]}]},{"type":"code_block","attrs":{"wrap":false,"language":"bash"},"content":[{"text":"# Pre-deployment checklist\nshellcheck script.sh\nbash -n script.sh\nbats test/script.bats\n./script.sh --help\nDEBUG=true ./script.sh","type":"text"}]},{"type":"heading","attrs":{"level":2},"content":[{"text":"Troubleshooting","type":"text"}]},{"type":"heading","attrs":{"level":3},"content":[{"text":"Script fails on a different platform","type":"text"}]},{"type":"bullet_list","content":[{"type":"list_item","content":[{"type":"paragraph","content":[{"text":"checkbashisms script.sh","type":"text","marks":[{"type":"code_inline"}]},{"text":" to surface non-portable constructs.","type":"text"}]}]},{"type":"list_item","content":[{"type":"paragraph","content":[{"text":"command -v tool","type":"text","marks":[{"type":"code_inline"}]},{"text":" to verify a required tool is installed.","type":"text"}]}]},{"type":"list_item","content":[{"type":"paragraph","content":[{"text":"Diff command flags between GNU and BSD (","type":"text"},{"text":"sed --version","type":"text","marks":[{"type":"code_inline"}]},{"text":" etc.).","type":"text"}]}]}]},{"type":"heading","attrs":{"level":3},"content":[{"text":"ShellCheck warnings","type":"text"}]},{"type":"bullet_list","content":[{"type":"list_item","content":[{"type":"paragraph","content":[{"text":"Read the rule explanation (","type":"text"},{"text":"shellcheck -W SC2086","type":"text","marks":[{"type":"code_inline"}]},{"text":").","type":"text"}]}]},{"type":"list_item","content":[{"type":"paragraph","content":[{"text":"Fix the underlying issue; only disable a rule with a justification comment.","type":"text"}]}]}]},{"type":"heading","attrs":{"level":3},"content":[{"text":"Works interactively but fails in cron","type":"text"}]},{"type":"bullet_list","content":[{"type":"list_item","content":[{"type":"paragraph","content":[{"text":"Cron has a minimal ","type":"text"},{"text":"PATH","type":"text","marks":[{"type":"code_inline"}]},{"text":" - set ","type":"text"},{"text":"PATH","type":"text","marks":[{"type":"code_inline"}]},{"text":" explicitly.","type":"text"}]}]},{"type":"list_item","content":[{"type":"paragraph","content":[{"text":"Use absolute paths.","type":"text"}]}]},{"type":"list_item","content":[{"type":"paragraph","content":[{"text":"Redirect stdout/stderr: ","type":"text"},{"text":"./script.sh >> /tmp/cron.log 2>&1","type":"text","marks":[{"type":"code_inline"}]},{"text":".","type":"text"}]}]}]},{"type":"heading","attrs":{"level":3},"content":[{"text":"Performance issues","type":"text"}]},{"type":"bullet_list","content":[{"type":"list_item","content":[{"type":"paragraph","content":[{"text":"Profile with ","type":"text"},{"text":"time","type":"text","marks":[{"type":"code_inline"}]},{"text":".","type":"text"}]}]},{"type":"list_item","content":[{"type":"paragraph","content":[{"text":"Enable ","type":"text"},{"text":"set -x","type":"text","marks":[{"type":"code_inline"}]},{"text":" to find slow steps.","type":"text"}]}]},{"type":"list_item","content":[{"type":"paragraph","content":[{"text":"Replace external invocations with Bash built-ins where possible.","type":"text"}]}]}]},{"type":"hr","attrs":{"markup":"---"}}]},"metadata":{"date":"2026-06-05","name":"bash-master","author":"@skillopedia","source":{"stars":39,"repo_name":"claude-plugin-marketplace","origin_url":"https://github.com/josiahsiegel/claude-plugin-marketplace/blob/HEAD/plugins/bash-master/skills/bash-master/SKILL.md","repo_owner":"josiahsiegel","body_sha256":"af43308238a559ba5879cfbb444e006777591de8639ce0a294ab5a3d952fdf61","cluster_key":"f278a04c96bdd3d1cfb336098c039de88b18b1d4db5150fe770fc7019dbe5f90","clean_bundle":{"format":"clean-skill-bundle-v1","source":"josiahsiegel/claude-plugin-marketplace/plugins/bash-master/skills/bash-master/SKILL.md","attachments":[{"id":"1d6d781b-cdc6-56b9-abd0-4f79f0eddd4f","key":"uploads/10433ee7-ad12-4ae0-b34e-97553e46c6c8/1d6d781b-cdc6-56b9-abd0-4f79f0eddd4f/attachment.md","path":"references/best_practices.md","size":29804,"sha256":"761361d3d9db2f54c51d8cbdd77c4de40cafbe4df4c4f2c14246337a4a1c7814","contentType":"text/markdown; charset=utf-8"},{"id":"a62c14b1-6f16-5f67-872a-54ca749ed3a4","key":"uploads/10433ee7-ad12-4ae0-b34e-97553e46c6c8/a62c14b1-6f16-5f67-872a-54ca749ed3a4/attachment.md","path":"references/in-depth-patterns.md","size":12305,"sha256":"40a226846d81fc87722205d0bdb1fb53c5cb50d71692b6142317ec0e529b1dca","contentType":"text/markdown; charset=utf-8"},{"id":"05594b80-9fe5-532a-81af-88b6b948937e","key":"uploads/10433ee7-ad12-4ae0-b34e-97553e46c6c8/05594b80-9fe5-532a-81af-88b6b948937e/attachment.md","path":"references/patterns_antipatterns.md","size":20553,"sha256":"005d25d1708a26abed44a5feafe69816c79cfed691be5d5a27b80dbcb495137d","contentType":"text/markdown; charset=utf-8"},{"id":"fe01b056-38c4-5ef3-be48-64850d3a2b0a","key":"uploads/10433ee7-ad12-4ae0-b34e-97553e46c6c8/fe01b056-38c4-5ef3-be48-64850d3a2b0a/attachment.md","path":"references/platform_specifics.md","size":25183,"sha256":"6c95018d53c48c0c00f57826e1e12b7a123a6ff62560fcd72b9fb7055e79f480","contentType":"text/markdown; charset=utf-8"},{"id":"6b90a0a4-f034-54b8-8583-49c0b01ed675","key":"uploads/10433ee7-ad12-4ae0-b34e-97553e46c6c8/6b90a0a4-f034-54b8-8583-49c0b01ed675/attachment.md","path":"references/resources.md","size":18739,"sha256":"1f5844996294b71fd25ca579bbe66f307b2799e8369a48b2f310096baece6bb8","contentType":"text/markdown; charset=utf-8"},{"id":"f0cc757e-6276-5a6e-9079-bcd747732e17","key":"uploads/10433ee7-ad12-4ae0-b34e-97553e46c6c8/f0cc757e-6276-5a6e-9079-bcd747732e17/attachment.md","path":"references/windows-git-bash-paths.md","size":18608,"sha256":"048869b039c3157359853d3cc919b069a81ad23693015a7fe082ebde385c4766","contentType":"text/markdown; charset=utf-8"}],"bundle_sha256":"23251665fa9bf61245c565897ef39e575ba2a772f680cd91a5f1a28e6c069258","attachment_count":6,"text_attachments":6,"attachment_storage":"skillopedia-attachments-v1","binary_attachments":0,"excluded_attachments":[]},"cluster_size":1,"skill_md_path":"plugins/bash-master/skills/bash-master/SKILL.md","import_metadata":{"date":"2026-06-05","author":"@skillopedia","version":"v1","category":"security","category_label":"Security"},"exact_dupes_collapsed_into_this":0},"version":"v1","category":"security","import_tag":"clean-skills-v1","description":"Expert bash/shell scripting across environments where Bash is available\n(Linux, macOS, Git Bash on Windows, WSL, containers). This is a Bash-focused\nskill - it does not provide PowerShell parity; on Windows the target is the\nBash interpreter (Git Bash / WSL), not native PowerShell.\nPROACTIVELY activate for: (1) ANY bash/shell script task, (2) System automation, (3) DevOps/CI/CD scripts, (4) Build/deployment automation, (5) Script review/debugging, (6) Converting commands to scripts.\nProvides: Google Shell Style Guide compliance, ShellCheck validation, Bash portability across Linux/macOS/WSL/Git Bash/containers, POSIX compliance, security hardening, error handling, performance optimization, testing with BATS, and production-ready patterns.\nEnsures professional-grade, secure, portable Bash scripts every time.\n"}},"renderedAt":1782979369138}

Bash Scripting Mastery Scope and platform contract This skill targets Bash itself , wherever Bash runs - Linux, macOS, WSL, Git Bash / MSYS2 on Windows, and Bash-based container images. It does not cover native PowerShell : a PowerShell script is a different language and should use . On Windows, assumes the user is running Bash inside Git Bash, WSL, or a similar Bash environment, and addresses the MSYS path-translation quirks that result. Repository conventions Project-level conventions (Windows backslashes in tool calls, documentation discipline, etc.) live in the agent body and the plugin.…