Bash Script Generator Overview Generate production-ready Bash scripts with clear requirements capture, deterministic generation flow, and validation-first iteration. Trigger Phrases Use this skill when the user asks to: - Create, generate, write, or build a Bash/shell script - Convert manual CLI steps into an automation script - Build a text-processing script using , , or - Create an operations helper script, cron script, or CI utility script Do not use this skill for validating an existing script only. Use for validation-only requests. Execution Model Follow stages in order. Do not skip a st…

\\n\\t'\n\nreadonly SCRIPT_DIR=\"$(cd \"$(dirname \"${BASH_SOURCE[0]}\")\" && pwd)\"\nreadonly SCRIPT_NAME=\"$(basename \"${BASH_SOURCE[0]}\")\"\nreadonly VERSION=\"1.0.0\"\n\nVERBOSE=false\nDRY_RUN=false\nLOG_LEVEL=1 # 0=DEBUG 1=INFO 2=WARN 3=ERROR\n\nusage() {\n cat \u003c\u003c EOF\nUsage: ${SCRIPT_NAME} [OPTIONS] [ARGUMENTS]\n\nDescription:\n Brief description of what the script does\n\nOptions:\n -h, --help Show this help message and exit\n -v, --verbose Enable verbose output\n -d, --debug Enable debug mode\n -n, --dry-run Perform dry run without making changes\n\nExamples:\n ${SCRIPT_NAME} -v file.txt\n ${SCRIPT_NAME} --dry-run input.txt output.txt\n\nEOF\n}\n\nlog() {\n local level=\"$1\"\n shift\n echo \"[${level}] $(date '+%Y-%m-%d %H:%M:%S') - $*\" >&2\n}\n\nlog_debug() { if [[ ${LOG_LEVEL} -le 0 ]]; then log \"DEBUG\" \"$@\"; fi; }\nlog_info() { if [[ ${LOG_LEVEL} -le 1 ]]; then log \"INFO\" \"$@\"; fi; }\nlog_warn() { if [[ ${LOG_LEVEL} -le 2 ]]; then log \"WARN\" \"$@\"; fi; }\nlog_error() { log \"ERROR\" \"$@\"; }\n\ndie() {\n log_error \"$@\"\n exit 1\n}\n\ncheck_command() {\n command -v \"$1\" &> /dev/null || die \"Required command not found: $1\"\n}\n\nvalidate_file() {\n [[ -f \"$1\" ]] || die \"File not found: $1\"\n [[ -r \"$1\" ]] || die \"File not readable: $1\"\n}\n\ncleanup() {\n local exit_code=$?\n log_debug \"Cleaning up...\"\n exit \"${exit_code}\"\n}\n\nparse_args() {\n while [[ $# -gt 0 ]]; do\n case \"$1\" in\n -h|--help) usage; exit 0 ;;\n -v|--verbose) VERBOSE=true; shift ;;\n -d|--debug) LOG_LEVEL=0; VERBOSE=true; shift ;;\n -n|--dry-run) DRY_RUN=true; shift ;;\n -*) die \"Unknown option: $1\" ;;\n *) break ;;\n esac\n done\n ARGS=(\"$@\")\n}\n\nmain() {\n parse_args \"$@\"\n\n log_info \"Starting ${SCRIPT_NAME}...\"\n\n # Main logic goes here\n\n log_info \"Completed successfully\"\n}\n\ntrap cleanup EXIT ERR INT TERM\n\nmain \"$@\"\n","content_type":"application/x-sh; charset=utf-8","language":"bash","size":2088,"content_sha256":"33f8fc548cb1add2fa12ed9f2d6ae0ba883f2b004346b11f0228c8a59c54c277"},{"filename":"docs/bash-scripting-guide.md","content":"# Bash Scripting Guide\n\n## Table of Contents\n\n1. [Introduction](#introduction)\n2. [Bash vs POSIX sh](#bash-vs-posix-sh)\n3. [Strict Mode and Error Handling](#strict-mode-and-error-handling)\n4. [Variables and Parameter Expansion](#variables-and-parameter-expansion)\n5. [Functions and Scope](#functions-and-scope)\n6. [Arrays and Associative Arrays](#arrays-and-associative-arrays)\n7. [Control Structures](#control-structures)\n8. [Process and Command Substitution](#process-and-command-substitution)\n9. [Best Practices](#best-practices)\n10. [Common Pitfalls](#common-pitfalls)\n\n## Introduction\n\nBash (Bourne Again Shell) is a powerful Unix shell and command language. This guide covers modern bash scripting practices and patterns for creating robust, maintainable scripts.\n\n## Bash vs POSIX sh\n\n### Key Differences\n\n**Bash-specific features (not in POSIX sh):**\n- Arrays: `arr=(one two three)`\n- Associative arrays: `declare -A map=([key]=value)`\n- `[[` conditional expressions\n- `$(( ))` arithmetic expansion with more operators\n- `${var//pattern/replacement}` parameter expansion\n- Process substitution: `\u003c(command)`\n- `select` keyword for menus\n- `**` recursive globbing with `shopt -s globstar`\n\n**POSIX sh compatible:**\n- Basic variable assignment and substitution\n- `[` test command (single brackets)\n- `case` statements\n- Basic parameter expansion\n- Command substitution with `$()`\n- Functions (with different syntax)\n\n### When to Choose\n\n**Use Bash when:**\n- Script runs on modern Linux/macOS systems\n- Need arrays or associative arrays\n- Want advanced string manipulation\n- Targeting bash-specific environments\n\n**Use POSIX sh when:**\n- Maximum portability required\n- Running on minimal systems (embedded, containers)\n- Need to run on different Unix variants\n- Following strict POSIX compliance requirements\n\n## Strict Mode and Error Handling\n\n### Essential: set -euo pipefail\n\n```bash\n#!/usr/bin/env bash\nset -euo pipefail\nIFS=

Bash Script Generator Overview Generate production-ready Bash scripts with clear requirements capture, deterministic generation flow, and validation-first iteration. Trigger Phrases Use this skill when the user asks to: - Create, generate, write, or build a Bash/shell script - Convert manual CLI steps into an automation script - Build a text-processing script using , , or - Create an operations helper script, cron script, or CI utility script Do not use this skill for validating an existing script only. Use for validation-only requests. Execution Model Follow stages in order. Do not skip a st…

\\n\\t'\n```\n\n**Explanation:**\n- `set -e` (errexit): Exit immediately if a command exits with non-zero status\n- `set -u` (nounset): Treat unset variables as an error\n- `set -o pipefail`: Return value of pipeline is status of last command to exit with non-zero status\n- `IFS=

Bash Script Generator Overview Generate production-ready Bash scripts with clear requirements capture, deterministic generation flow, and validation-first iteration. Trigger Phrases Use this skill when the user asks to: - Create, generate, write, or build a Bash/shell script - Convert manual CLI steps into an automation script - Build a text-processing script using , , or - Create an operations helper script, cron script, or CI utility script Do not use this skill for validating an existing script only. Use for validation-only requests. Execution Model Follow stages in order. Do not skip a st…

\\n\\t'`: Set Internal Field Separator to newline and tab only (prevents word splitting issues)\n\n### When to Disable Strict Mode Temporarily\n\n```bash\n# Disable errexit for commands that are expected to fail\nset +e\ncommand_that_might_fail\nexit_code=$?\nset -e\n\n# Or use || true for single commands\ncommand_that_might_fail || true\n\n# Or handle error explicitly\nif ! command_that_might_fail; then\n echo \"Command failed, but continuing...\"\nfi\n```\n\n### Signal Handling with trap\n\n```bash\n# Cleanup function\ncleanup() {\n local exit_code=$?\n echo \"Cleaning up...\" >&2\n rm -f \"${temp_file}\"\n exit \"${exit_code}\"\n}\n\n# Set traps\ntrap cleanup EXIT # Always run cleanup on exit\ntrap cleanup ERR # Run cleanup on error\ntrap cleanup INT TERM # Run cleanup on interrupt or termination\n\n# Create temp file\ntemp_file=$(mktemp)\n\n# Rest of script...\n```\n\n### Error Handling Patterns\n\n```bash\n# Pattern 1: Die function\ndie() {\n echo \"ERROR: $*\" >&2\n exit 1\n}\n\n[[ -f \"${file}\" ]] || die \"File not found: ${file}\"\n\n# Pattern 2: Check function return values\nif ! do_something; then\n echo \"do_something failed\" >&2\n return 1\nfi\n\n# Pattern 3: Command substitution with error handling\noutput=$(command 2>&1) || {\n echo \"Command failed: ${output}\" >&2\n exit 1\n}\n\n# Pattern 4: Validate prerequisites\ncheck_command() {\n command -v \"$1\" &> /dev/null || die \"Required command not found: $1\"\n}\n\ncheck_command \"jq\"\ncheck_command \"curl\"\n```\n\n## Variables and Parameter Expansion\n\n### Variable Naming Conventions\n\n```bash\n# Constants - uppercase with readonly\nreadonly MAX_RETRIES=3\nreadonly CONFIG_FILE=\"/etc/myapp/config.conf\"\n\n# Environment variables - uppercase\nexport PATH=\"${HOME}/bin:${PATH}\"\nexport LOG_LEVEL=\"INFO\"\n\n# Local variables - lowercase\nlocal counter=0\nlocal temp_file=\"\"\n\n# Function names - lowercase with underscores\nprocess_data() {\n local input=\"$1\"\n # ...\n}\n```\n\n### Always Quote Variables\n\n```bash\n# Good - properly quoted\nrm \"${file}\"\ncp \"${source}\" \"${destination}\"\necho \"Value: ${variable}\"\n\n# Bad - unquoted (prone to word splitting and globbing)\nrm $file\ncp $source $destination\necho \"Value: $variable\"\n```\n\n### Parameter Expansion\n\n```bash\n# Default values\n${var:-default} # Use default if var is unset or empty\n${var:=default} # Set var to default if unset or empty\n${var:?error message} # Exit with error message if var is unset or empty\n${var:+alternative} # Use alternative if var is set\n\n# String manipulation\n${var#pattern} # Remove shortest match from beginning\n${var##pattern} # Remove longest match from beginning\n${var%pattern} # Remove shortest match from end\n${var%%pattern} # Remove longest match from end\n${var/pattern/replacement} # Replace first match\n${var//pattern/replacement} # Replace all matches\n${var^} # Uppercase first character\n${var^^} # Uppercase all characters\n${var,} # Lowercase first character\n${var,,} # Lowercase all characters\n\n# Length and substring\n${#var} # Length of var\n${var:offset} # Substring from offset to end\n${var:offset:length} # Substring from offset with length\n\n# Examples\nfile=\"/path/to/file.txt\"\n${file##*/} # file.txt (basename)\n${file%.*} # /path/to/file (remove extension)\n${file##*.} # txt (extension only)\n${file%/*} # /path/to (dirname)\n```\n\n## Functions and Scope\n\n### Function Definition\n\n```bash\n# POSIX style (portable)\nfunction_name() {\n # function body\n}\n\n# Bash-specific (not portable to sh)\nfunction function_name {\n # function body\n}\n\n# Recommended: POSIX style with local variables\nprocess_file() {\n local input_file=\"$1\"\n local output_file=\"$2\"\n\n # Process file\n grep \"pattern\" \"${input_file}\" > \"${output_file}\"\n}\n```\n\n### Variable Scope\n\n```bash\n# Global variable\nGLOBAL_VAR=\"global\"\n\nmy_function() {\n # Local variable - only visible in function\n local local_var=\"local\"\n\n # Modifying global variable\n GLOBAL_VAR=\"modified\"\n\n # Function parameter access\n local param1=\"$1\"\n local param2=\"$2\"\n\n echo \"Params: ${param1} ${param2}\"\n}\n\nmy_function \"arg1\" \"arg2\"\n```\n\n### Return Values\n\n```bash\n# Functions return exit status (0-255)\ncheck_file() {\n local file=\"$1\"\n [[ -f \"${file}\" ]] && return 0 || return 1\n}\n\n# Use function return status\nif check_file \"data.txt\"; then\n echo \"File exists\"\nfi\n\n# Return data via stdout\nget_value() {\n echo \"computed value\"\n}\n\n# Capture output\nresult=$(get_value)\n\n# Return data via variable (using nameref in bash 4.3+)\nget_data() {\n local -n result_var=$1\n result_var=\"computed value\"\n}\n\nget_data my_result\necho \"${my_result}\"\n```\n\n## Arrays and Associative Arrays\n\n### Indexed Arrays (Bash-specific)\n\n```bash\n# Array creation\narr=() # Empty array\narr=(one two three) # Initialize with values\narr[0]=\"first\" # Assign to specific index\n\n# Array operations\narr+=(\"four\") # Append\n${arr[0]} # Access element\n${arr[@]} # All elements (as separate words)\n${arr[*]} # All elements (as single word)\n${#arr[@]} # Number of elements\n${!arr[@]} # Indices\n\n# Iterating over array\nfor item in \"${arr[@]}\"; do\n echo \"${item}\"\ndone\n\n# Iterating with indices\nfor i in \"${!arr[@]}\"; do\n echo \"Index $i: ${arr[i]}\"\ndone\n\n# Array slicing\n${arr[@]:offset:length} # Slice array\n\n# Remove element\nunset 'arr[1]' # Remove specific element\n```\n\n### Associative Arrays (Bash 4.0+)\n\n```bash\n# Declaration required\ndeclare -A map\n\n# Assignment\nmap[key1]=\"value1\"\nmap[key2]=\"value2\"\n\n# Or initialize\ndeclare -A map=([key1]=\"value1\" [key2]=\"value2\")\n\n# Access\n${map[key1]} # Get value\n${map[@]} # All values\n${!map[@]} # All keys\n${#map[@]} # Number of elements\n\n# Check if key exists\nif [[ -v map[key1] ]]; then\n echo \"key1 exists\"\nfi\n\n# Iterate over keys and values\nfor key in \"${!map[@]}\"; do\n echo \"${key}: ${map[${key}]}\"\ndone\n```\n\n### POSIX Alternative to Arrays\n\n```bash\n# Use positional parameters\nset -- one two three\n\n# Access\necho \"$1\" # one\necho \"$2\" # two\necho \"$#\" # count: 3\n\n# Iterate\nfor item in \"$@\"; do\n echo \"${item}\"\ndone\n\n# Add item\nset -- \"$@\" \"four\"\n\n# Remove first item\nshift\n```\n\n## Control Structures\n\n### Conditional Expressions\n\n```bash\n# Bash [[ ... ]] (recommended for bash)\nif [[ -f \"${file}\" ]]; then\n echo \"File exists\"\nfi\n\nif [[ \"${var}\" == \"value\" ]]; then\n echo \"Match\"\nfi\n\nif [[ \"${var}\" =~ ^[0-9]+$ ]]; then\n echo \"Numeric\"\nfi\n\n# POSIX [ ... ] (portable)\nif [ -f \"${file}\" ]; then\n echo \"File exists\"\nfi\n\n# File tests\n[[ -e file ]] # Exists\n[[ -f file ]] # Regular file\n[[ -d file ]] # Directory\n[[ -L file ]] # Symbolic link\n[[ -r file ]] # Readable\n[[ -w file ]] # Writable\n[[ -x file ]] # Executable\n[[ -s file ]] # Not empty\n\n# String tests\n[[ -z \"${var}\" ]] # Empty string\n[[ -n \"${var}\" ]] # Non-empty string\n[[ \"${a}\" == \"${b}\" ]] # Equal\n[[ \"${a}\" != \"${b}\" ]] # Not equal\n[[ \"${a}\" \u003c \"${b}\" ]] # Lexicographically less (bash only)\n\n# Numeric tests\n[[ \"${a}\" -eq \"${b}\" ]] # Equal\n[[ \"${a}\" -ne \"${b}\" ]] # Not equal\n[[ \"${a}\" -lt \"${b}\" ]] # Less than\n[[ \"${a}\" -le \"${b}\" ]] # Less than or equal\n[[ \"${a}\" -gt \"${b}\" ]] # Greater than\n[[ \"${a}\" -ge \"${b}\" ]] # Greater than or equal\n\n# Logical operators\n[[ condition1 && condition2 ]] # AND\n[[ condition1 || condition2 ]] # OR\n[[ ! condition ]] # NOT\n```\n\n### case Statements\n\n```bash\ncase \"${var}\" in\n pattern1)\n # commands\n ;;\n pattern2|pattern3)\n # Multiple patterns\n ;;\n *)\n # Default case\n ;;\nesac\n\n# Example with patterns\ncase \"${file}\" in\n *.txt)\n echo \"Text file\"\n ;;\n *.jpg|*.png)\n echo \"Image file\"\n ;;\n *)\n echo \"Unknown type\"\n ;;\nesac\n```\n\n### Loops\n\n```bash\n# while loop\nwhile condition; do\n # commands\ndone\n\n# until loop\nuntil condition; do\n # commands\ndone\n\n# for loop (C-style, bash only)\nfor ((i=0; i\u003c10; i++)); do\n echo \"${i}\"\ndone\n\n# for loop (iterating over values)\nfor item in one two three; do\n echo \"${item}\"\ndone\n\n# for loop (iterating over files)\nfor file in *.txt; do\n echo \"${file}\"\ndone\n\n# for loop (iterating over command output)\nwhile IFS= read -r line; do\n echo \"${line}\"\ndone \u003c file.txt\n\n# Or with command substitution (avoid for large output)\nfor file in $(find . -name \"*.txt\"); do\n echo \"${file}\"\ndone\n```\n\n## Process and Command Substitution\n\n### Command Substitution\n\n```bash\n# Recommended: $( ... )\nresult=$(command)\nresult=$(command arg1 arg2)\n\n# Nested command substitution\nouter=$(echo \"Inner: $(echo \"value\")\")\n\n# Not recommended: backticks (legacy)\nresult=`command`\n```\n\n### Process Substitution (Bash-specific)\n\n```bash\n# \u003c( ... ) creates a named pipe/file descriptor\n# Treat command output as a file\n\n# Compare output of two commands\ndiff \u003c(ls dir1) \u003c(ls dir2)\n\n# Use multiple inputs\npaste \u003c(cut -f1 file1) \u003c(cut -f2 file2)\n\n# Output redirection with process substitution\ncommand > >(tee stdout.log) 2> >(tee stderr.log >&2)\n```\n\n## Best Practices\n\n### Script Structure\n\n```bash\n#!/usr/bin/env bash\nset -euo pipefail\nIFS=

Bash Script Generator Overview Generate production-ready Bash scripts with clear requirements capture, deterministic generation flow, and validation-first iteration. Trigger Phrases Use this skill when the user asks to: - Create, generate, write, or build a Bash/shell script - Convert manual CLI steps into an automation script - Build a text-processing script using , , or - Create an operations helper script, cron script, or CI utility script Do not use this skill for validating an existing script only. Use for validation-only requests. Execution Model Follow stages in order. Do not skip a st…

\\n\\t'\n\n# ============================================================================\n# Script Name: example.sh\n# Description: Brief description\n# Author: Your Name\n# Created: 2025-01-23\n# ============================================================================\n\n# Constants\nreadonly SCRIPT_DIR=\"$(cd \"$(dirname \"${BASH_SOURCE[0]}\")\" && pwd)\"\nreadonly SCRIPT_NAME=\"$(basename \"${BASH_SOURCE[0]}\")\"\n\n# Global variables\nVERBOSE=false\nDRY_RUN=false\n\n# Functions\nusage() {\n # ...\n}\n\ncleanup() {\n # ...\n}\n\nmain() {\n # ...\n}\n\n# Signal handlers\ntrap cleanup EXIT ERR INT TERM\n\n# Execute main\nmain \"$@\"\n```\n\n### Always Use Quotes\n\n```bash\n# Good\necho \"${variable}\"\ncp \"${source}\" \"${dest}\"\n[[ -f \"${file}\" ]]\n\n# Bad (unsafe)\necho $variable\ncp $source $dest\n[[ -f $file ]]\n```\n\n### Use readonly for Constants\n\n```bash\nreadonly MAX_RETRIES=3\nreadonly CONFIG_FILE=\"/etc/config\"\n```\n\n### Prefer $() Over Backticks\n\n```bash\n# Good\noutput=$(command)\nresult=$(first $(second))\n\n# Bad\noutput=`command`\nresult=`first \\`second\\`` # Hard to read\n```\n\n### Check Command Existence\n\n```bash\nif ! command -v required_cmd &> /dev/null; then\n echo \"Error: required_cmd not found\" >&2\n exit 1\nfi\n```\n\n### Validate Inputs\n\n```bash\n# Check argument count\nif [[ $# -lt 1 ]]; then\n echo \"Usage: $0 \u003cfile>\" >&2\n exit 1\nfi\n\n# Validate file exists\n[[ -f \"${file}\" ]] || { echo \"File not found: ${file}\" >&2; exit 1; }\n\n# Validate numeric input\n[[ \"${count}\" =~ ^[0-9]+$ ]] || { echo \"Count must be numeric\" >&2; exit 1; }\n```\n\n## Common Pitfalls\n\n### Word Splitting\n\n```bash\n# Problem: Filename with spaces\nfile=\"my file.txt\"\nrm $file # Tries to remove \"my\" and \"file.txt\"\n\n# Solution: Quote variables\nrm \"${file}\" # Correctly removes \"my file.txt\"\n```\n\n### Globbing\n\n```bash\n# Problem: Pattern in variable\npattern=\"*.txt\"\necho $pattern # Expands to list of .txt files\n\n# Solution: Quote to prevent globbing\necho \"${pattern}\" # Prints \"*.txt\"\n```\n\n### Useless Use of Cat (UUOC)\n\n```bash\n# Bad: Unnecessary cat\ncat file.txt | grep \"pattern\"\n\n# Good: Direct input\ngrep \"pattern\" file.txt\n\n# Bad: cat in loop\ncat file.txt | while read line; do\n echo \"${line}\"\ndone\n\n# Good: redirect to while\nwhile read -r line; do\n echo \"${line}\"\ndone \u003c file.txt\n```\n\n### Not Handling Spaces in Filenames\n\n```bash\n# Bad: Will break on filenames with spaces\nfor file in $(find . -name \"*.txt\"); do\n process \"${file}\"\ndone\n\n# Good: Use while read\nfind . -name \"*.txt\" -print0 | while IFS= read -r -d '' file; do\n process \"${file}\"\ndone\n\n# Or use globbing\nfor file in ./**/*.txt; do\n process \"${file}\"\ndone\n```\n\n### Ignoring Command Exit Status\n\n```bash\n# Bad: Ignoring failure\ncommand_that_might_fail\nnext_command\n\n# Good: Check exit status\nif command_that_might_fail; then\n next_command\nelse\n echo \"Command failed\" >&2\n exit 1\nfi\n\n# Or with errexit\ncommand_that_might_fail || { echo \"Failed\" >&2; exit 1; }\n```\n\n---\n\n## References\n\n- [GNU Bash Manual](https://www.gnu.org/software/bash/manual/bash.html)\n- [Google Shell Style Guide](https://google.github.io/styleguide/shellguide.html)\n- [ShellCheck](https://www.shellcheck.net/) - Script analysis tool\n- [Bash Guide for Beginners](https://tldp.org/LDP/Bash-Beginners-Guide/html/)","content_type":"text/markdown; charset=utf-8","language":"markdown","size":14937,"content_sha256":"1b820e47eb01f4cc4da0acc1d39c9703061d67d952c342a877cb9e6b95ab5b58"},{"filename":"docs/generation-best-practices.md","content":"# Script Generation Best Practices\n\nGuidelines for generating high-quality, maintainable bash scripts.\n\n## Core Principles\n\n1. **Security First** - Validate inputs, quote variables, avoid injection\n2. **Fail Fast** - Use strict mode, check errors immediately\n3. **Self-Documenting** - Clear names, usage text, comments for complex logic\n4. **Testable** - Modular functions, predictable behavior\n5. **Maintainable** - Consistent style, organized structure\n\n## Script Structure Template\n\n```bash\n#!/usr/bin/env bash\n#\n# Script Name: descriptive-name.sh\n# Description: What it does in one line\n# Usage: script.sh [OPTIONS] ARGUMENTS\n# Author: Name\n# Created: Date\n#\n\nset -euo pipefail\nIFS=

Bash Script Generator Overview Generate production-ready Bash scripts with clear requirements capture, deterministic generation flow, and validation-first iteration. Trigger Phrases Use this skill when the user asks to: - Create, generate, write, or build a Bash/shell script - Convert manual CLI steps into an automation script - Build a text-processing script using , , or - Create an operations helper script, cron script, or CI utility script Do not use this skill for validating an existing script only. Use for validation-only requests. Execution Model Follow stages in order. Do not skip a st…

\\n\\t'\n\n# Constants (UPPERCASE, readonly)\nreadonly SCRIPT_DIR=\"$(cd \"$(dirname \"${BASH_SOURCE[0]}\")\" && pwd)\"\nreadonly SCRIPT_NAME=\"$(basename \"${BASH_SOURCE[0]}\")\"\n\n# Global variables (lowercase or Mixed_Case)\nverbose=false\ndry_run=false\n\n# Functions (lowercase_with_underscores)\nusage() { }\ncleanup() { }\nmain() { }\n\n# Signal handlers\ntrap cleanup EXIT ERR INT TERM\n\n# Execute\nmain \"$@\"\n```\n\n## Naming Conventions\n\n```bash\n# Constants - UPPERCASE with readonly\nreadonly MAX_RETRIES=3\nreadonly CONFIG_FILE=\"/etc/app.conf\"\n\n# Environment variables - UPPERCASE\nexport PATH=\"${HOME}/bin:${PATH}\"\nexport LOG_LEVEL=\"INFO\"\n\n# Global variables - lowercase or Mixed_Case\nscript_version=\"1.0.0\"\ntemp_directory=\"\"\n\n# Functions - lowercase_with_underscores\nprocess_file() { }\nsend_notification() { }\n\n# Local variables - lowercase\nlocal count=0\nlocal file_path=\"\"\n```\n\n## Security Best Practices\n\n```bash\n# 1. Always quote variables\nrm \"${file}\" # Good\nrm $file # Bad\n\n# 2. Validate all inputs\n[[ \"${input}\" =~ ^[a-zA-Z0-9_-]+$ ]] || die \"Invalid input\"\n\n# 3. Never use eval with user input\neval \"${user_command}\" # Dangerous!\n\n# 4. Validate file paths\n[[ \"${file}\" =~ /etc ]] && die \"Cannot modify /etc\"\n[[ -f \"${file}\" ]] || die \"File not found\"\n\n# 5. Use $() instead of backticks\noutput=$(command) # Good\noutput=`command` # Bad\n\n# 6. Set safe IFS\nIFS=

Bash Script Generator Overview Generate production-ready Bash scripts with clear requirements capture, deterministic generation flow, and validation-first iteration. Trigger Phrases Use this skill when the user asks to: - Create, generate, write, or build a Bash/shell script - Convert manual CLI steps into an automation script - Build a text-processing script using , , or - Create an operations helper script, cron script, or CI utility script Do not use this skill for validating an existing script only. Use for validation-only requests. Execution Model Follow stages in order. Do not skip a st…

\\n\\t'\n```\n\n## Error Handling Patterns\n\n```bash\n# Pattern 1: Die function\ndie() {\n echo \"ERROR: $*\" >&2\n exit 1\n}\n\n# Pattern 2: Check prerequisites\ncheck_command() {\n command -v \"$1\" &> /dev/null || die \"Required: $1\"\n}\n\n# Pattern 3: Validate inputs\n[[ $# -ge 1 ]] || die \"Usage: $0 FILE\"\n[[ -f \"$1\" ]] || die \"File not found: $1\"\n\n# Pattern 4: Cleanup on exit\ncleanup() {\n [[ -n \"${temp_dir:-}\" ]] && rm -rf \"${temp_dir}\"\n}\ntrap cleanup EXIT\n```\n\n## Function Design\n\n```bash\n# Good function design\n#######################################\n# Process a log file and extract errors\n# Globals:\n# LOG_LEVEL\n# Arguments:\n# $1 - Path to log file\n# $2 - Output file (optional)\n# Outputs:\n# Writes errors to stdout or file\n# Returns:\n# 0 on success, 1 on error\n#######################################\nprocess_log_file() {\n local log_file=\"$1\"\n local output_file=\"${2:-}\"\n\n # Validate\n [[ -f \"${log_file}\" ]] || return 1\n\n # Process\n local errors\n errors=$(grep \"ERROR\" \"${log_file}\")\n\n # Output\n if [[ -n \"${output_file}\" ]]; then\n echo \"${errors}\" > \"${output_file}\"\n else\n echo \"${errors}\"\n fi\n\n return 0\n}\n```\n\n## Code Organization\n\n```bash\n# Recommended order:\n1. Shebang and header comments\n2. Strict mode settings\n3. Constants\n4. Global variables\n5. Helper functions (general → specific)\n6. Main logic functions\n7. Main function\n8. Signal handlers\n9. Main execution\n```\n\n## Generated Code Quality Checklist\n\n- [ ] Proper shebang: `#!/usr/bin/env bash`\n- [ ] Strict mode enabled: `set -euo pipefail`\n- [ ] All variables quoted: `\"${var}\"`\n- [ ] Constants marked readonly\n- [ ] Functions documented\n- [ ] Error handling implemented\n- [ ] Usage/help function included\n- [ ] Input validation present\n- [ ] Cleanup on exit (trap)\n- [ ] No ShellCheck warnings\n- [ ] Comments for complex logic\n- [ ] Consistent formatting\n\n## References\n\n- [Google Shell Style Guide](https://google.github.io/styleguide/shellguide.html)\n- [ShellCheck](https://www.shellcheck.net/)","content_type":"text/markdown; charset=utf-8","language":"markdown","size":4139,"content_sha256":"3b37922795468a75149202d3e184a34971df6cb3454cf30719e128dee3f4e6e5"},{"filename":"docs/script-patterns.md","content":"# Bash Script Patterns\n\nCommon patterns and templates for bash script generation.\n\n## Table of Contents\n\n1. [Argument Parsing Patterns](#argument-parsing-patterns)\n2. [Configuration File Handling](#configuration-file-handling)\n3. [Logging Frameworks](#logging-frameworks)\n4. [Parallel Processing](#parallel-processing)\n5. [Lock Files](#lock-files)\n6. [Signal Handling](#signal-handling)\n7. [Retry Logic](#retry-logic)\n\n## Argument Parsing Patterns\n\n### Simple getopts Pattern\n\n```bash\n#!/usr/bin/env bash\nset -euo pipefail\n\nusage() {\n cat \u003c\u003c EOF\nUsage: ${0##*/} [OPTIONS] FILE\n\nOptions:\n -h Show this help\n -v Verbose output\n -f FILE Input file\n -o FILE Output file\nEOF\n}\n\nmain() {\n local verbose=false\n local input_file=\"\"\n local output_file=\"\"\n\n while getopts \":hvf:o:\" opt; do\n case ${opt} in\n h) usage; exit 0 ;;\n v) verbose=true ;;\n f) input_file=\"${OPTARG}\" ;;\n o) output_file=\"${OPTARG}\" ;;\n :) echo \"Option -${OPTARG} requires an argument\" >&2; exit 1 ;;\n \\?) echo \"Invalid option: -${OPTARG}\" >&2; exit 1 ;;\n esac\n done\n shift $((OPTIND - 1))\n\n # Validation\n [[ -n \"${input_file}\" ]] || { echo \"Error: -f required\" >&2; exit 1; }\n\n # Process\n echo \"Processing ${input_file}...\"\n}\n\nmain \"$@\"\n```\n\n### Long Options Pattern\n\n```bash\n# Parse both short and long options\nparse_args() {\n while [[ $# -gt 0 ]]; do\n case \"$1\" in\n -h|--help)\n usage\n exit 0\n ;;\n -v|--verbose)\n VERBOSE=true\n shift\n ;;\n -f|--file)\n INPUT_FILE=\"$2\"\n shift 2\n ;;\n -o|--output)\n OUTPUT_FILE=\"$2\"\n shift 2\n ;;\n --)\n shift\n break\n ;;\n -*)\n echo \"Unknown option: $1\" >&2\n exit 1\n ;;\n *)\n break\n ;;\n esac\n done\n\n # Remaining arguments\n REMAINING_ARGS=(\"$@\")\n}\n```\n\n### Subcommand Pattern\n\n```bash\n#!/usr/bin/env bash\nset -euo pipefail\n\ncmd_start() {\n echo \"Starting service...\"\n}\n\ncmd_stop() {\n echo \"Stopping service...\"\n}\n\ncmd_status() {\n echo \"Checking status...\"\n}\n\nusage() {\n cat \u003c\u003c EOF\nUsage: ${0##*/} COMMAND [OPTIONS]\n\nCommands:\n start Start the service\n stop Stop the service\n status Check service status\n\nOptions:\n -h, --help Show this help\nEOF\n}\n\nmain() {\n [[ $# -lt 1 ]] && { usage; exit 1; }\n\n local command=\"$1\"\n shift\n\n case \"${command}\" in\n start) cmd_start \"$@\" ;;\n stop) cmd_stop \"$@\" ;;\n status) cmd_status \"$@\" ;;\n -h|--help) usage; exit 0 ;;\n *) echo \"Unknown command: ${command}\" >&2; usage; exit 1 ;;\n esac\n}\n\nmain \"$@\"\n```\n\n## Configuration File Handling\n\n### Source-based Configuration\n\n```bash\n# config.conf file\nCONFIG_VALUE=\"something\"\nMAX_RETRIES=3\nAPI_URL=\"https://api.example.com\"\n\n# In script\nload_config() {\n local config_file=\"${1:-config.conf}\"\n\n if [[ -f \"${config_file}\" ]]; then\n # shellcheck source=/dev/null\n source \"${config_file}\"\n else\n echo \"Warning: Config file not found: ${config_file}\" >&2\n fi\n}\n\nload_config \"/etc/myapp/config.conf\"\n```\n\n### Key-Value Configuration Parser\n\n```bash\n# config.conf format:\n# key=value\n# # comments\n\nload_config() {\n local config_file=\"$1\"\n\n while IFS='=' read -r key value; do\n # Skip empty lines and comments\n [[ -z \"${key}\" || \"${key}\" =~ ^[[:space:]]*# ]] && continue\n\n # Trim whitespace\n key=$(echo \"${key}\" | tr -d '[:space:]')\n value=$(echo \"${value}\" | sed 's/^[[:space:]]*//;s/[[:space:]]*$//')\n\n # Export as variable\n declare -g \"${key}=${value}\"\n done \u003c \"${config_file}\"\n}\n```\n\n### INI-style Configuration Parser\n\n```bash\n# Parse INI format [section] key=value\nparse_ini() {\n local file=\"$1\"\n local section=\"\"\n\n while IFS= read -r line; do\n # Skip empty lines and comments\n [[ -z \"${line}\" || \"${line}\" =~ ^[[:space:]]*[#;] ]] && continue\n\n # Section header\n if [[ \"${line}\" =~ ^\\[([^]]+)\\] ]]; then\n section=\"${BASH_REMATCH[1]}\"\n continue\n fi\n\n # Key=value\n if [[ \"${line}\" =~ ^([^=]+)=(.*)$ ]]; then\n local key=\"${BASH_REMATCH[1]}\"\n local value=\"${BASH_REMATCH[2]}\"\n key=$(echo \"${key}\" | tr -d '[:space:]')\n value=$(echo \"${value}\" | sed 's/^[[:space:]]*//;s/[[:space:]]*$//')\n\n # Store in associative array\n config[\"${section}.${key}\"]=\"${value}\"\n fi\n done \u003c \"${file}\"\n}\n```\n\n## Logging Frameworks\n\n### Simple Logging with Levels\n\n```bash\n# LOG_LEVEL: 0=DEBUG, 1=INFO (default), 2=WARN, 3=ERROR\nLOG_LEVEL=${LOG_LEVEL:-1}\n\n# Use if-form guards — the && short-circuit form returns 1 when the\n# level check fails, which triggers set -e at the call site.\nlog_debug() { if [[ ${LOG_LEVEL} -le 0 ]]; then echo \"[DEBUG] $(date '+%Y-%m-%d %H:%M:%S') $*\" >&2; fi; }\nlog_info() { if [[ ${LOG_LEVEL} -le 1 ]]; then echo \"[INFO] $(date '+%Y-%m-%d %H:%M:%S') $*\" >&2; fi; }\nlog_warn() { if [[ ${LOG_LEVEL} -le 2 ]]; then echo \"[WARN] $(date '+%Y-%m-%d %H:%M:%S') $*\" >&2; fi; }\nlog_error() { echo \"[ERROR] $(date '+%Y-%m-%d %H:%M:%S') $*\" >&2; }\n```\n\n### File-based Logging\n\n```bash\nreadonly LOG_FILE=\"${LOG_FILE:-/var/log/myscript.log}\"\n\nlog_to_file() {\n local level=\"$1\"\n shift\n echo \"[${level}] $(date '+%Y-%m-%d %H:%M:%S') $*\" >> \"${LOG_FILE}\"\n}\n\nlog_info() {\n local msg=\"$*\"\n echo \"[INFO] ${msg}\" >&2\n log_to_file \"INFO\" \"${msg}\"\n}\n```\n\n### Structured JSON Logging\n\n```bash\nlog_json() {\n local level=\"$1\"\n local message=\"$2\"\n local timestamp=$(date -u '+%Y-%m-%dT%H:%M:%SZ')\n\n cat \u003c\u003cEOF\n{\"timestamp\":\"${timestamp}\",\"level\":\"${level}\",\"message\":\"${message}\",\"script\":\"${SCRIPT_NAME}\"}\nEOF\n}\n\nlog_info() {\n log_json \"INFO\" \"$*\" >&2\n}\n```\n\n## Parallel Processing\n\n### Using xargs for Parallel Execution\n\n```bash\n# Process files in parallel\nfind . -name \"*.txt\" -print0 | xargs -0 -P 4 -I {} process_file {}\n\n# With function export\nprocess_file() {\n echo \"Processing $1...\"\n # ... processing logic\n}\nexport -f process_file\n\nfind . -name \"*.txt\" | xargs -P 4 -I {} bash -c 'process_file \"$@\"' _ {}\n```\n\n### Using GNU Parallel\n\n```bash\n# Requires: apt-get install parallel\n\n# Simple parallel execution\nparallel process_file ::: file1.txt file2.txt file3.txt\n\n# From file list\ncat files.txt | parallel process_file\n\n# With progress bar\nparallel --bar process_file ::: *.txt\n\n# Control number of jobs\nparallel -j 4 process_file ::: *.txt\n```\n\n### Background Jobs Pattern\n\n```bash\n# Track background jobs\npids=()\n\n# Start jobs\nfor file in *.txt; do\n process_file \"${file}\" &\n pids+=($!)\ndone\n\n# Wait for all jobs\nfor pid in \"${pids[@]}\"; do\n if wait \"${pid}\"; then\n echo \"Job ${pid} completed successfully\"\n else\n echo \"Job ${pid} failed\" >&2\n fi\ndone\n```\n\n## Lock Files\n\n### Simple Lock File\n\n```bash\nreadonly LOCK_FILE=\"/var/lock/myscript.lock\"\n\nacquire_lock() {\n if [[ -f \"${LOCK_FILE}\" ]]; then\n echo \"Another instance is running (lock file exists)\" >&2\n exit 1\n fi\n\n echo $ > \"${LOCK_FILE}\"\n trap 'rm -f \"${LOCK_FILE}\"' EXIT\n}\n\nacquire_lock\n```\n\n### PID-based Lock with Stale Lock Detection\n\n```bash\nacquire_lock() {\n local lock_file=\"/var/lock/myscript.lock\"\n\n if [[ -f \"${lock_file}\" ]]; then\n local old_pid=$(cat \"${lock_file}\")\n\n # Check if process is still running\n if kill -0 \"${old_pid}\" 2>/dev/null; then\n echo \"Another instance (PID ${old_pid}) is running\" >&2\n return 1\n else\n echo \"Removing stale lock file\" >&2\n rm -f \"${lock_file}\"\n fi\n fi\n\n echo $ > \"${lock_file}\"\n trap 'rm -f \"${lock_file}\"' EXIT\n}\n```\n\n### Using flock for Atomic Locking\n\n```bash\n# Requires flock command\n\nexec 200>/var/lock/myscript.lock\nflock -n 200 || { echo \"Another instance is running\" >&2; exit 1; }\n\n# Script runs exclusively\n# Lock is released when script exits\n```\n\n## Signal Handling\n\n### Cleanup on Exit\n\n```bash\ncleanup() {\n local exit_code=$?\n echo \"Cleaning up...\" >&2\n\n # Remove temp files\n [[ -n \"${temp_dir:-}\" ]] && rm -rf \"${temp_dir}\"\n\n # Release locks\n [[ -f \"${lock_file:-}\" ]] && rm -f \"${lock_file}\"\n\n exit \"${exit_code}\"\n}\n\ntrap cleanup EXIT\n```\n\n### Handling Multiple Signals\n\n```bash\nhandle_sigint() {\n echo \"Received SIGINT, cleaning up...\" >&2\n cleanup\n exit 130 # Standard exit code for SIGINT\n}\n\nhandle_sigterm() {\n echo \"Received SIGTERM, cleaning up...\" >&2\n cleanup\n exit 143 # Standard exit code for SIGTERM\n}\n\ntrap handle_sigint INT\ntrap handle_sigterm TERM\ntrap cleanup EXIT ERR\n```\n\n### Graceful Shutdown\n\n```bash\nSHUTDOWN=false\n\nhandle_signal() {\n echo \"Shutdown signal received, finishing current work...\" >&2\n SHUTDOWN=true\n}\n\ntrap handle_signal INT TERM\n\n# Main processing loop\nwhile [[ \"${SHUTDOWN}\" == \"false\" ]]; do\n process_next_item || break\ndone\n\necho \"Graceful shutdown complete\" >&2\n```\n\n## Retry Logic\n\n### Simple Retry with Backoff\n\n```bash\nretry() {\n local max_attempts=3\n local delay=1\n local attempt=1\n\n while [[ ${attempt} -le ${max_attempts} ]]; do\n if \"$@\"; then\n return 0\n else\n echo \"Attempt ${attempt} failed, retrying in ${delay}s...\" >&2\n sleep \"${delay}\"\n ((attempt++))\n ((delay*=2)) # Exponential backoff\n fi\n done\n\n echo \"All ${max_attempts} attempts failed\" >&2\n return 1\n}\n\n# Usage\nretry curl -f https://api.example.com/data\n```\n\n### Advanced Retry with Custom Parameters\n\n```bash\nretry_with_backoff() {\n local max_attempts=\"${1}\"\n local delay=\"${2}\"\n local max_delay=\"${3:-60}\"\n shift 3\n local attempt=1\n\n while [[ ${attempt} -le ${max_attempts} ]]; do\n if \"$@\"; then\n return 0\n fi\n\n if [[ ${attempt} -lt ${max_attempts} ]]; then\n echo \"Attempt ${attempt}/${max_attempts} failed\" >&2\n echo \"Retrying in ${delay}s...\" >&2\n sleep \"${delay}\"\n\n # Exponential backoff with max cap\n delay=$((delay * 2))\n [[ ${delay} -gt ${max_delay} ]] && delay=${max_delay}\n fi\n\n ((attempt++))\n done\n\n echo \"All ${max_attempts} attempts failed\" >&2\n return 1\n}\n\n# Usage: retry_with_backoff MAX_ATTEMPTS INITIAL_DELAY MAX_DELAY command args...\nretry_with_backoff 5 1 30 curl -f https://api.example.com/data\n```\n\n### Retry with Jitter\n\n```bash\nretry_with_jitter() {\n local max_attempts=\"$1\"\n local base_delay=\"$2\"\n shift 2\n local attempt=1\n\n while [[ ${attempt} -le ${max_attempts} ]]; do\n if \"$@\"; then\n return 0\n fi\n\n if [[ ${attempt} -lt ${max_attempts} ]]; then\n # Add random jitter (0-100% of delay)\n local jitter=$((RANDOM % base_delay))\n local delay=$((base_delay + jitter))\n\n echo \"Attempt ${attempt} failed, retrying in ${delay}s...\" >&2\n sleep \"${delay}\"\n\n # Exponential backoff\n ((base_delay*=2))\n fi\n\n ((attempt++))\n done\n\n return 1\n}\n```\n\n---\n\n## References\n\n- [Advanced Bash-Scripting Guide](https://tldp.org/LDP/abs/html/)\n- [Bash Hackers Wiki](https://wiki.bash-hackers.org/)\n- [Google Shell Style Guide](https://google.github.io/styleguide/shellguide.html)","content_type":"text/markdown; charset=utf-8","language":"markdown","size":11685,"content_sha256":"f729e7e0030ef9fbc77475af0c17e68228eb596fca0886ba5a7ceaa6b0a83bd7"},{"filename":"docs/text-processing-guide.md","content":"# Text Processing Guide\n\nGuide for choosing and using grep, awk, sed, and other text processing tools effectively in bash scripts.\n\n## Decision Tree: Which Tool to Use?\n\n```\nIs it a simple pattern match/filter?\n├─ YES → Use grep\n└─ NO\n ├─ Is it field/column-based data?\n │ └─ YES → Use awk\n └─ NO\n ├─ Is it find-and-replace or deletion?\n │ └─ YES → Use sed\n └─ NO\n └─ Complex processing → Use awk or consider Python/Perl\n```\n\n## grep: Pattern Matching and Filtering\n\n### When to Use grep\n- Searching for patterns in files\n- Filtering lines by regex\n- Simple line extraction\n- Counting matches\n- Finding files containing patterns\n\n### Common grep Patterns\n\n```bash\n# Basic search\ngrep \"pattern\" file.txt\n\n# Case-insensitive\ngrep -i \"error\" log.txt\n\n# Invert match (lines NOT containing pattern)\ngrep -v \"DEBUG\" log.txt\n\n# Count matches\ngrep -c \"ERROR\" log.txt\n\n# Show line numbers\ngrep -n \"TODO\" *.sh\n\n# Extended regex (ERE)\ngrep -E \"(error|fail|critical)\" log.txt\n\n# Recursive directory search\ngrep -r \"function_name\" src/\n\n# Show filename only\ngrep -l \"pattern\" *.txt\n\n# Show context (lines before/after)\ngrep -A 2 -B 2 \"ERROR\" log.txt # 2 lines after and before\n\n# Multiple patterns\ngrep -e \"error\" -e \"fail\" log.txt\n\n# Read patterns from file\ngrep -f patterns.txt input.txt\n\n# Whole word match\ngrep -w \"test\" file.txt # Matches \"test\" but not \"testing\"\n\n# Fixed string (not regex)\ngrep -F \"a.b\" file.txt # Matches literal \"a.b\", not regex\n\n# Binary file handling\ngrep -a \"pattern\" binary_file # Treat binary as text\n```\n\n### grep for Log Analysis\n\n```bash\n# Extract error messages from last hour\nfind /var/log -name \"*.log\" -mmin -60 -exec grep \"ERROR\" {} +\n\n# Count errors by type\ngrep \"ERROR\" app.log | cut -d':' -f3 | sort | uniq -c | sort -rn\n\n# Find errors excluding known issues\ngrep \"ERROR\" app.log | grep -v -f known_errors.txt\n```\n\n## awk: Field-Based Text Processing\n\n### When to Use awk\n- Processing structured data (CSV, logs, tables)\n- Extracting specific fields\n- Performing calculations\n- Generating reports\n- Complex conditional logic on fields\n\n### awk Basics\n\n```bash\n# Print specific fields (space-delimited by default)\nawk '{print $1, $3}' file.txt\n\n# Custom delimiter\nawk -F',' '{print $1, $3}' data.csv\nawk -F':' '{print $1}' /etc/passwd\n\n# Multiple delimiters\nawk -F'[,:]' '{print $1}' file.txt\n\n# Print last field\nawk '{print $NF}' file.txt\n\n# Print all but first field\nawk '{$1=\"\"; print $0}' file.txt\n```\n\n### awk Conditionals\n\n```bash\n# Print lines where field 3 > 100\nawk '$3 > 100' data.txt\n\n# Print lines where field matches pattern\nawk '$2 ~ /error/' log.txt\n\n# Print lines where field does NOT match\nawk '$2 !~ /DEBUG/' log.txt\n\n# Multiple conditions\nawk '$3 > 100 && $4 \u003c 500' data.txt\n\n# If-else logic\nawk '{if ($3 > 100) print \"High:\", $0; else print \"Low:\", $0}' data.txt\n```\n\n### awk Calculations\n\n```bash\n# Sum values in column 3\nawk '{sum += $3} END {print sum}' numbers.txt\n\n# Average\nawk '{sum += $3; count++} END {print sum/count}' numbers.txt\n\n# Find max value\nawk 'BEGIN {max=0} {if ($1 > max) max=$1} END {print max}' numbers.txt\n\n# Count lines matching condition\nawk '$3 > 100 {count++} END {print count}' data.txt\n```\n\n### awk Formatted Output\n\n```bash\n# Printf-style formatting\nawk '{printf \"Name: %-20s Age: %3d\\n\", $1, $2}' people.txt\n\n# Tab-separated output\nawk 'BEGIN {OFS=\"\\t\"} {print $1, $2, $3}' file.txt\n\n# Custom output formatting\nawk '{printf \"%s: %10.2f\\n\", $1, $2}' data.txt\n```\n\n### awk Built-in Variables\n\n```bash\nNF # Number of fields in current line\nNR # Current line number\nFNR # Line number in current file\nFS # Input field separator\nOFS # Output field separator\nRS # Input record separator\nORS # Output record separator\nFILENAME # Current filename\n\n# Examples\nawk '{print NR, NF, $0}' file.txt # Line number, field count, full line\nawk 'NR==10' file.txt # Print line 10\nawk 'NF > 5' file.txt # Lines with more than 5 fields\n```\n\n### awk for Log Analysis\n\n```bash\n# Apache/Nginx access log analysis\n# Extract status codes and count\nawk '{print $9}' access.log | sort | uniq -c | sort -rn\n\n# Summarize traffic by IP\nawk '{ip[$1]++} END {for (i in ip) print ip[i], i}' access.log | sort -rn\n\n# Calculate average response time (field 11)\nawk '{sum += $11; count++} END {print sum/count}' access.log\n\n# Extract requests by hour\nawk '{print substr($4, 2, 14)}' access.log | uniq -c\n```\n\n## sed: Stream Editing\n\n### When to Use sed\n- Find and replace operations\n- Deleting specific lines\n- In-place file editing\n- Simple transformations\n\n### sed Substitution\n\n```bash\n# Basic substitution (first occurrence per line)\nsed 's/old/new/' file.txt\n\n# Global substitution (all occurrences)\nsed 's/old/new/g' file.txt\n\n# Case-insensitive substitution\nsed 's/old/new/gi' file.txt\n\n# In-place editing\nsed -i 's/old/new/g' file.txt\n\n# Backup before in-place edit\nsed -i.bak 's/old/new/g' file.txt\n\n# Replace only on specific line\nsed '5s/old/new/' file.txt\n\n# Replace on lines matching pattern\nsed '/ERROR/s/old/new/g' file.txt\n\n# Use different delimiter\nsed 's|/usr/local|/opt|g' file.txt\n\n# Backreferences\nsed 's/\\([0-9]*\\)-\\([0-9]*\\)/\\2-\\1/' file.txt\n\n# Multiple substitutions\nsed -e 's/foo/bar/g' -e 's/baz/qux/g' file.txt\n```\n\n### sed Deletion\n\n```bash\n# Delete specific line\nsed '5d' file.txt\n\n# Delete range of lines\nsed '5,10d' file.txt\n\n# Delete lines matching pattern\nsed '/pattern/d' file.txt\n\n# Delete empty lines\nsed '/^$/d' file.txt\n\n# Delete lines NOT matching pattern\nsed '/pattern/!d' file.txt\n```\n\n### sed Line Operations\n\n```bash\n# Print specific line\nsed -n '10p' file.txt\n\n# Print range\nsed -n '10,20p' file.txt\n\n# Print lines matching pattern\nsed -n '/ERROR/p' file.txt\n\n# Insert line before match\nsed '/pattern/i\\New line before' file.txt\n\n# Append line after match\nsed '/pattern/a\\New line after' file.txt\n\n# Change entire line\nsed '/pattern/c\\Replacement line' file.txt\n```\n\n### sed Advanced Patterns\n\n```bash\n# Remove comments\nsed 's/#.*//' file.txt\n\n# Remove leading whitespace\nsed 's/^[ \\t]*//' file.txt\n\n# Remove trailing whitespace\nsed 's/[ \\t]*$//' file.txt\n\n# Remove HTML tags\nsed 's/\u003c[^>]*>//g' file.html\n\n# Extract text between delimiters\nsed -n 's/.*\u003ctitle>\\(.*\\)\u003c\\/title>.*/\\1/p' file.html\n```\n\n## Combining Tools: Pipeline Patterns\n\n### grep + awk\n\n```bash\n# Filter then extract fields\ngrep \"ERROR\" log.txt | awk '{print $1, $5}'\n\n# Filter multiple patterns, process\ngrep -E \"ERROR|WARN\" log.txt | awk '{count[$2]++} END {for (i in count) print i, count[i]}'\n```\n\n### sed + awk\n\n```bash\n# Clean then process\nsed 's/[^[:print:]]//g' data.txt | awk '{sum += $2} END {print sum}'\n\n# Remove comments, extract fields\nsed 's/#.*//' config.txt | awk -F'=' '{print $1}'\n```\n\n### Complete Pipeline Example\n\n```bash\n# Analyze web server logs\ncat access.log \\\n | grep \"GET\" \\\n | grep -v \"robot\" \\\n | sed 's/.*HTTP\\/[0-9.]*\" //' \\\n | awk '$1 >= 200 && $1 \u003c 300 {success++} $1 >= 400 {fail++} END {print \"Success:\", success, \"Fail:\", fail}'\n```\n\n## Performance Tips\n\n### grep Performance\n\n```bash\n# Use -F for fixed strings (faster than regex)\ngrep -F \"literal.string\" large_file.txt\n\n# Use -m to stop after N matches\ngrep -m 10 \"pattern\" large_file.txt\n\n# Parallel grep for large files\nparallel -j4 grep \"pattern\" ::: chunk1 chunk2 chunk3 chunk4\n```\n\n### awk Performance\n\n```bash\n# Exit early if possible\nawk '{if (condition) {print; exit}}' large_file.txt\n\n# Process only needed lines\nawk 'NR > 1000 {exit} {process}' large_file.txt\n\n# Use built-in functions efficiently\nawk '{count[$1]++} END {for (i in count) print i, count[i]}' file.txt\n```\n\n### sed Performance\n\n```bash\n# Minimize patterns\nsed -e 's/a/b/g' -e 's/c/d/g' file.txt # Better than multiple sed calls\n\n# Use in-place editing for large files\nsed -i 's/old/new/g' large_file.txt # Avoids loading entire file\n```\n\n### Avoid Useless Use of cat\n\n```bash\n# Bad\ncat file.txt | grep \"pattern\"\ncat file.txt | awk '{print $1}'\ncat file.txt | sed 's/old/new/g'\n\n# Good\ngrep \"pattern\" file.txt\nawk '{print $1}' file.txt\nsed 's/old/new/g' file.txt\n```\n\n## Real-World Examples\n\n### Example 1: CSV Processing\n\n```bash\n# Extract specific columns from CSV\nawk -F',' '{print $1, $3, $5}' data.csv\n\n# Filter rows by value\nawk -F',' '$3 > 1000 {print $0}' data.csv\n\n# Calculate sum per category\nawk -F',' '{sum[$1] += $3} END {for (cat in sum) print cat, sum[cat]}' sales.csv\n```\n\n### Example 2: Log Analysis\n\n```bash\n# Error rate over time\ngrep \"ERROR\" app.log \\\n | awk '{print $1}' \\\n | uniq -c \\\n | awk '{print $2, $1}'\n\n# Top 10 error messages\ngrep \"ERROR\" app.log \\\n | sed 's/.*ERROR: //' \\\n | sort \\\n | uniq -c \\\n | sort -rn \\\n | head -10\n```\n\n### Example 3: Configuration File Processing\n\n```bash\n# Extract non-comment, non-empty lines\nsed -e 's/#.*//' -e '/^$/d' config.txt\n\n# Convert KEY=VALUE to JSON\nawk -F'=' 'BEGIN {print \"{\"} {printf \" \\\"%s\\\": \\\"%s\\\",\\n\", $1, $2} END {print \"}\"}' config.txt\n```\n\n---\n\n## References\n\n- [GNU grep Manual](https://www.gnu.org/software/grep/manual/grep.html)\n- [GNU awk Manual](https://www.gnu.org/software/gawk/manual/gawk.html)\n- [GNU sed Manual](https://www.gnu.org/software/sed/manual/sed.html)\n- [The Art of Command Line](https://github.com/jlevy/the-art-of-command-line)","content_type":"text/markdown; charset=utf-8","language":"markdown","size":9340,"content_sha256":"d8c0f3bf724a29f425686d77f4f4d1234a741a4cfcbb2a33b96788444595a816"},{"filename":"examples/log-analyzer.sh","content":"#!/usr/bin/env bash\nset -euo pipefail\n\nusage() {\n cat \u003c\u003c EOF\nUsage: ${0##*/} [OPTIONS] LOG_FILE\n\nAnalyze log files and generate summary reports\n\nOptions:\n -h Show this help\n -t TYPE Report type: errors|summary (default: summary)\n -o FILE Output file (default: stdout)\n\nExamples:\n ${0##*/} application.log\n ${0##*/} -t errors -o errors.txt application.log\nEOF\n}\n\nanalyze_errors() {\n local log_file=\"$1\"\n\n echo \"Error Summary:\"\n echo \"==============\"\n\n grep \"ERROR\" \"${log_file}\" \\\n | sed 's/.*ERROR: //' \\\n | sed 's/ -.*//' \\\n | sort \\\n | uniq -c \\\n | sort -rn \\\n | awk '{count=$1; $1=\"\"; sub(/^ /,\"\"); printf \" %-40s %6d\\n\", $0, count}'\n\n echo \"\"\n echo \"Total errors: $(grep -c \"ERROR\" \"${log_file}\" 2>/dev/null || true)\"\n}\n\ngenerate_summary() {\n local log_file=\"$1\"\n\n echo \"Log File Analysis Summary\"\n echo \"=========================\"\n echo \"\"\n echo \"File: ${log_file}\"\n echo \"Total lines: $(wc -l \u003c \"${log_file}\")\"\n echo \"\"\n\n echo \"Log Levels:\"\n for level in DEBUG INFO WARN ERROR FATAL; do\n local count\n count=$(grep -c \"${level}\" \"${log_file}\" 2>/dev/null || true)\n printf \" %-10s %6d\\n\" \"${level}:\" \"${count}\"\n done\n}\n\nmain() {\n local report_type=\"summary\"\n local output_file=\"\"\n local log_file=\"\"\n\n while getopts \":ht:o:\" opt; do\n case ${opt} in\n h) usage; exit 0 ;;\n t) report_type=\"${OPTARG}\" ;;\n o) output_file=\"${OPTARG}\" ;;\n :) echo \"Option -${OPTARG} requires an argument\" >&2; exit 1 ;;\n \\?) echo \"Invalid option: -${OPTARG}\" >&2; exit 1 ;;\n esac\n done\n shift $((OPTIND - 1))\n\n log_file=\"${1:-}\"\n [[ -n \"${log_file}\" ]] || { echo \"Error: LOG_FILE required\" >&2; usage; exit 1; }\n [[ -f \"${log_file}\" ]] || { echo \"Error: File not found: ${log_file}\" >&2; exit 1; }\n\n local output\n case \"${report_type}\" in\n errors) output=$(analyze_errors \"${log_file}\") ;;\n summary) output=$(generate_summary \"${log_file}\") ;;\n *) echo \"Invalid report type: ${report_type}\" >&2; exit 1 ;;\n esac\n\n if [[ -n \"${output_file}\" ]]; then\n echo \"${output}\" > \"${output_file}\"\n echo \"Report saved to: ${output_file}\"\n else\n echo \"${output}\"\n fi\n}\n\nmain \"$@\"\n","content_type":"application/x-sh; charset=utf-8","language":"bash","size":2354,"content_sha256":"db63a1c5cd9c500580eb377dd6e127e05a0319a623d49cdd173a69389d0bdd8d"},{"filename":"scripts/generate_script_template.sh","content":"#!/usr/bin/env bash\n#\n# Generate bash script templates\n#\n\nset -euo pipefail\n\nreadonly SCRIPT_DIR=\"$(cd \"$(dirname \"${BASH_SOURCE[0]}\")\" && pwd)\"\nreadonly TEMPLATES_DIR=\"${SCRIPT_DIR}/../assets/templates\"\n\nlist_templates() {\n local found=false\n\n for template_path in \"${TEMPLATES_DIR}\"/*-template.sh; do\n if [[ -f \"${template_path}\" ]]; then\n found=true\n basename \"${template_path}\" | sed 's/-template.sh$//'\n fi\n done\n\n if [[ \"${found}\" == \"false\" ]]; then\n echo \"(none)\"\n fi\n}\n\ndefault_output_file() {\n local template_type=\"$1\"\n echo \"./${template_type}-script.sh\"\n}\n\nvalidate_template_type() {\n local value=\"$1\"\n\n # Block traversal payloads and path separators explicitly.\n if [[ \"$value\" == *\"/\"* || \"$value\" == *\"..\"* ]]; then\n echo \"Error: Invalid TEMPLATE_TYPE: ${value}\" >&2\n echo \"Allowed characters: letters, digits, '_' and '-'\" >&2\n return 1\n fi\n\n if [[ ! \"$value\" =~ ^[a-zA-Z0-9_-]+$ ]]; then\n echo \"Error: Invalid TEMPLATE_TYPE: ${value}\" >&2\n echo \"Allowed characters: letters, digits, '_' and '-'\" >&2\n return 1\n fi\n}\n\nusage() {\n cat \u003c\u003c EOF\nUsage: ${0##*/} TEMPLATE_TYPE [OUTPUT_FILE]\n\nGenerate a bash script from a template.\n\nTemplates include:\n - Proper shebang and strict mode (set -euo pipefail)\n - Logging functions (debug, info, warn, error)\n - Error handling (die, check_command, validate_file)\n - Argument parsing with getopts\n - Cleanup trap handlers\n - Usage documentation\n\nExamples:\n ${0##*/} standard\n ${0##*/} standard myscript.sh\n ${0##*/} standard /usr/local/bin/deploy.sh\n\nAvailable templates:\n$(list_templates)\n\nEOF\n}\n\nmain() {\n local template_type\n local output_file\n local template_file\n local output_dir\n\n if [[ $# -eq 0 ]]; then\n echo \"Error: TEMPLATE_TYPE is required\" >&2\n usage\n exit 1\n fi\n\n if [[ \"${1:-}\" == \"-h\" || \"${1:-}\" == \"--help\" ]]; then\n usage\n exit 0\n fi\n\n if [[ $# -gt 2 ]]; then\n echo \"Error: Too many arguments\" >&2\n usage\n exit 1\n fi\n\n template_type=\"$1\"\n validate_template_type \"$template_type\" || exit 1\n output_file=\"${2:-$(default_output_file \"${template_type}\")}\"\n template_file=\"${TEMPLATES_DIR}/${template_type}-template.sh\"\n\n if [[ ! -f \"${template_file}\" ]]; then\n echo \"Error: Template not found: ${template_type}\" >&2\n echo \"Available templates:\" >&2\n while IFS= read -r template_name; do\n echo \" ${template_name}\" >&2\n done \u003c \u003c(list_templates)\n exit 1\n fi\n\n output_dir=\"$(dirname \"${output_file}\")\"\n if [[ \"${output_dir}\" != \".\" ]]; then\n mkdir -p \"${output_dir}\"\n fi\n\n cp \"${template_file}\" \"${output_file}\"\n chmod u+x \"${output_file}\"\n\n echo \"Created script: ${output_file}\"\n echo \"Template: ${template_type}\"\n echo \"Source: ${template_file}\"\n}\n\nmain \"$@\"\n","content_type":"application/x-sh; charset=utf-8","language":"bash","size":2961,"content_sha256":"92a2341ab7f75e2e23a0d133780ce630015a607a1d71f48145f29deaccc44fb3"},{"filename":"scripts/run_ci_checks.sh","content":"#!/usr/bin/env bash\n#\n# Deterministic CI validation entrypoint for bash-script-generator.\n# Runs:\n# 1) bash -n syntax checks\n# 2) shellcheck -x checks (optional or required)\n# 3) regression tests (scripts/test_generator.sh)\n#\n\nset -euo pipefail\n\nreadonly SCRIPT_DIR=\"$(cd \"$(dirname \"${BASH_SOURCE[0]}\")\" && pwd)\"\nreadonly SKILL_DIR=\"$(cd \"${SCRIPT_DIR}/..\" && pwd)\"\nreadonly TEST_RUNNER=\"${SCRIPT_DIR}/test_generator.sh\"\n\nusage() {\n cat \u003c\u003cEOF\nUsage: ${0##*/} [OPTIONS]\n\nRun deterministic checks for bash-script-generator.\n\nOptions:\n --require-shellcheck Fail if shellcheck is unavailable.\n --skip-shellcheck Skip shellcheck stage.\n --skip-regression-tests Skip scripts/test_generator.sh.\n -h, --help Show this help message.\n\nEnvironment:\n SHELLCHECK_BIN Override shellcheck binary/path (default: shellcheck)\n CI=true|1 Defaults to --require-shellcheck unless explicitly overridden\nEOF\n}\n\nis_true() {\n local value=\"$1\"\n [[ \"$value\" == \"true\" || \"$value\" == \"1\" ]]\n}\n\ncommand_is_available() {\n local command_name=\"$1\"\n if [[ \"$command_name\" == */* ]]; then\n [[ -x \"$command_name\" ]]\n else\n command -v \"$command_name\" >/dev/null 2>&1\n fi\n}\n\ncollect_shell_files() {\n SHELL_FILES=()\n while IFS= read -r file; do\n SHELL_FILES+=(\"$file\")\n done \u003c \u003c(\n {\n find \"${SCRIPT_DIR}\" -maxdepth 1 -type f -name \"*.sh\"\n find \"${SKILL_DIR}/examples\" -maxdepth 1 -type f -name \"*.sh\"\n find \"${SKILL_DIR}/assets/templates\" -maxdepth 1 -type f -name \"*.sh\"\n } | LC_ALL=C sort\n )\n\n if [[ \"${#SHELL_FILES[@]}\" -eq 0 ]]; then\n echo \"Error: No shell files found to validate.\" >&2\n return 1\n fi\n}\n\nrun_syntax_checks() {\n echo \"[1/3] bash -n syntax checks\"\n local shell_file\n for shell_file in \"${SHELL_FILES[@]}\"; do\n bash -n \"${shell_file}\"\n done\n echo \" PASS: bash -n succeeded for ${#SHELL_FILES[@]} file(s)\"\n}\n\nrun_shellcheck_checks() {\n local shellcheck_bin=\"$1\"\n local require_shellcheck=\"$2\"\n local skip_shellcheck=\"$3\"\n\n if [[ \"$skip_shellcheck\" -eq 1 ]]; then\n echo \"[2/3] shellcheck -x checks\"\n echo \" SKIP: shellcheck stage disabled via --skip-shellcheck\"\n return 0\n fi\n\n echo \"[2/3] shellcheck -x checks\"\n if ! command_is_available \"$shellcheck_bin\"; then\n if [[ \"$require_shellcheck\" -eq 1 ]]; then\n echo \"Error: shellcheck is required but not available (${shellcheck_bin}).\" >&2\n return 1\n fi\n echo \" SKIP: shellcheck unavailable (${shellcheck_bin}); continuing without shellcheck\"\n return 0\n fi\n\n local shell_file\n for shell_file in \"${SHELL_FILES[@]}\"; do\n \"$shellcheck_bin\" -x \"${shell_file}\"\n done\n echo \" PASS: shellcheck succeeded for ${#SHELL_FILES[@]} file(s)\"\n}\n\nrun_regression_tests() {\n local skip_regression_tests=\"$1\"\n\n echo \"[3/3] regression tests\"\n if [[ \"$skip_regression_tests\" -eq 1 ]]; then\n echo \" SKIP: regression suite disabled via --skip-regression-tests\"\n return 0\n fi\n\n bash \"${TEST_RUNNER}\"\n}\n\nmain() {\n local require_shellcheck=0\n local skip_shellcheck=0\n local skip_regression_tests=0\n local shellcheck_mode_overridden=0\n local shellcheck_bin=\"${SHELLCHECK_BIN:-shellcheck}\"\n\n while [[ $# -gt 0 ]]; do\n case \"$1\" in\n --require-shellcheck)\n require_shellcheck=1\n skip_shellcheck=0\n shellcheck_mode_overridden=1\n ;;\n --skip-shellcheck)\n skip_shellcheck=1\n require_shellcheck=0\n shellcheck_mode_overridden=1\n ;;\n --skip-regression-tests)\n skip_regression_tests=1\n ;;\n -h|--help)\n usage\n exit 0\n ;;\n *)\n echo \"Error: Unknown option: $1\" >&2\n usage\n exit 1\n ;;\n esac\n shift\n done\n\n if [[ \"$shellcheck_mode_overridden\" -eq 0 ]] && is_true \"${CI:-}\"; then\n require_shellcheck=1\n fi\n\n if [[ \"$skip_shellcheck\" -eq 1 && \"$require_shellcheck\" -eq 1 ]]; then\n echo \"Error: --skip-shellcheck and --require-shellcheck cannot be used together.\" >&2\n exit 1\n fi\n\n export LC_ALL=C\n export LANG=C\n export TZ=UTC\n\n collect_shell_files\n run_syntax_checks\n run_shellcheck_checks \"$shellcheck_bin\" \"$require_shellcheck\" \"$skip_shellcheck\"\n run_regression_tests \"$skip_regression_tests\"\n\n echo \"\"\n echo \"All configured CI checks passed.\"\n}\n\nmain \"$@\"\n","content_type":"application/x-sh; charset=utf-8","language":"bash","size":4722,"content_sha256":"50e31d9aceb0c09a0380adf4e6673b600cfe03169d30cc211f30ed0f75ad4826"},{"filename":"scripts/test_generator.sh","content":"#!/usr/bin/env bash\n#\n# Regression test suite for bash-script-generator\n#\n# Tests:\n# 1. generate_script_template.sh — argument handling and file generation\n# 2. log-analyzer.sh — functional behaviour\n# 3. run_ci_checks.sh — deterministic validation wiring\n#\n# Exit 0 when all assertions pass; non-zero on any failure.\n#\n\nset -euo pipefail\n\nSCRIPT_DIR=\"$(cd \"$(dirname \"${BASH_SOURCE[0]}\")\" && pwd)\"\nreadonly SCRIPT_DIR\nGENERATOR=\"$SCRIPT_DIR/generate_script_template.sh\"\nCI_RUNNER=\"$SCRIPT_DIR/run_ci_checks.sh\"\nLOG_ANALYZER=\"$SCRIPT_DIR/../examples/log-analyzer.sh\"\n\nPASS=0\nFAIL=0\n\n# ─── helpers ────────────────────────────────────────────────────────────────\n\npass() { echo \" PASS: $1\"; PASS=$((PASS + 1)); }\nfail() { echo \" FAIL: $1\"; FAIL=$((FAIL + 1)); }\n\n# Run a command silently and return its exit code without aborting this script.\nrun_exit_code() {\n local exit_code=0\n \"$@\" >/dev/null 2>&1 || exit_code=$?\n echo \"$exit_code\"\n}\n\nassert_exit_code() {\n local label=\"$1\"\n local expected=\"$2\"\n shift 2\n\n local actual\n actual=$(run_exit_code \"$@\")\n\n if [[ \"$actual\" -eq \"$expected\" ]]; then\n pass \"$label (exit $actual)\"\n else\n fail \"$label — expected exit $expected, got $actual\"\n echo \" --- command output ---\"\n \"$@\" 2>&1 | sed 's/^/ /' || true\n echo \" --- end output ---\"\n fi\n}\n\n# Assert that a pattern IS present in the combined stdout+stderr of a command.\nassert_output_contains() {\n local label=\"$1\"\n local pattern=\"$2\"\n shift 2\n\n local output\n output=$(\"$@\" 2>&1 || true)\n\n if echo \"$output\" | grep -qE \"$pattern\"; then\n pass \"$label\"\n else\n fail \"$label — pattern not found: $pattern\"\n echo \" --- command output ---\"\n echo \"$output\" | sed 's/^/ /'\n echo \" --- end output ---\"\n fi\n}\n\n# Assert that a pattern is NOT present in the combined stdout+stderr of a command.\nassert_output_not_contains() {\n local label=\"$1\"\n local pattern=\"$2\"\n shift 2\n\n local output\n output=$(\"$@\" 2>&1 || true)\n\n if echo \"$output\" | grep -qE \"$pattern\"; then\n fail \"$label — unexpected pattern found: $pattern\"\n echo \" --- command output ---\"\n echo \"$output\" | sed 's/^/ /'\n echo \" --- end output ---\"\n else\n pass \"$label\"\n fi\n}\n\n# ─── setup ──────────────────────────────────────────────────────────────────\n\nTEMP_DIR=$(mktemp -d)\ntrap 'rm -rf \"${TEMP_DIR}\"' EXIT\n\n# Fixture log file used by log-analyzer tests\nLOG_FILE=\"${TEMP_DIR}/app.log\"\ncat > \"$LOG_FILE\" \u003c\u003c 'EOF'\n2024-01-15 10:00:01 INFO: App started\n2024-01-15 10:00:02 DEBUG: Loading config\n2024-01-15 10:00:03 ERROR: Connection refused to database\n2024-01-15 10:00:04 ERROR: Connection refused to database\n2024-01-15 10:00:05 WARN: Retry attempt\n2024-01-15 10:00:06 ERROR: Timeout on upstream request\n2024-01-15 10:00:07 INFO: Request complete\n2024-01-15 10:00:08 FATAL: Critical failure\nEOF\n\necho \"Running bash-script-generator tests...\"\n\n# ─── generate_script_template.sh: argument handling ─────────────────────────\n\necho \"\"\necho \"[generate_script_template.sh — argument handling]\"\n\nassert_exit_code \\\n \"no args exits non-zero\" \\\n 1 \\\n bash \"$GENERATOR\"\n\nassert_exit_code \\\n \"--help exits 0\" \\\n 0 \\\n bash \"$GENERATOR\" --help\n\nassert_exit_code \\\n \"-h exits 0\" \\\n 0 \\\n bash \"$GENERATOR\" -h\n\nassert_exit_code \\\n \"unknown template exits non-zero\" \\\n 1 \\\n bash \"$GENERATOR\" nonexistent-template\n\nassert_exit_code \\\n \"too many args exits non-zero\" \\\n 1 \\\n bash \"$GENERATOR\" standard out.sh extra-arg\n\nassert_exit_code \\\n \"traversal template_type payload is rejected\" \\\n 1 \\\n bash \"$GENERATOR\" ../templates/standard\n\nassert_output_contains \\\n \"traversal payload shows invalid template_type error\" \\\n \"Invalid TEMPLATE_TYPE\" \\\n bash \"$GENERATOR\" ../templates/standard\n\nassert_exit_code \\\n \"slash and dot traversal payload is rejected\" \\\n 1 \\\n bash \"$GENERATOR\" standard/../../evil\n\nassert_output_contains \\\n \"slash and dot traversal payload shows invalid template_type error\" \\\n \"Invalid TEMPLATE_TYPE\" \\\n bash \"$GENERATOR\" standard/../../evil\n\nassert_output_contains \\\n \"no-args error mentions TEMPLATE_TYPE\" \\\n \"TEMPLATE_TYPE\" \\\n bash \"$GENERATOR\"\n\nassert_output_contains \\\n \"unknown template error lists available templates\" \\\n \"Available templates\" \\\n bash \"$GENERATOR\" nonexistent-template\n\n# ─── generate_script_template.sh: file generation ───────────────────────────\n\necho \"\"\necho \"[generate_script_template.sh — file generation]\"\n\nOUTPUT=\"${TEMP_DIR}/generated.sh\"\nassert_exit_code \\\n \"standard template with explicit output exits 0\" \\\n 0 \\\n bash \"$GENERATOR\" standard \"$OUTPUT\"\n\nif [[ -f \"$OUTPUT\" ]]; then\n pass \"output file was created\"\nelse\n fail \"output file was not created\"\nfi\n\nif [[ -x \"$OUTPUT\" ]]; then\n pass \"output file is executable (chmod u+x applied)\"\nelse\n fail \"output file is not executable\"\nfi\n\nassert_output_contains \\\n \"generated file has bash shebang\" \\\n \"#!/usr/bin/env bash\" \\\n cat \"$OUTPUT\"\n\nassert_output_contains \\\n \"generated file has strict mode\" \\\n \"set -euo pipefail\" \\\n cat \"$OUTPUT\"\n\nassert_output_contains \\\n \"generated file has numeric LOG_LEVEL\" \\\n \"LOG_LEVEL=1\" \\\n cat \"$OUTPUT\"\n\n# Syntax check: the generated script must be parseable by bash\nif bash -n \"$OUTPUT\" 2>/dev/null; then\n pass \"generated file passes bash -n syntax check\"\nelse\n fail \"generated file has syntax errors\"\nfi\n\n# Overwrite: generating into an existing path must succeed silently\nassert_exit_code \\\n \"overwriting existing output file exits 0\" \\\n 0 \\\n bash \"$GENERATOR\" standard \"$OUTPUT\"\n\n# Nested directories must be created automatically\nNESTED=\"${TEMP_DIR}/a/b/c/nested.sh\"\nassert_exit_code \\\n \"output into non-existent nested directory exits 0\" \\\n 0 \\\n bash \"$GENERATOR\" standard \"$NESTED\"\n\nif [[ -f \"$NESTED\" ]]; then\n pass \"nested output file was created\"\nelse\n fail \"nested output file was not created\"\nfi\n\n# Default output path: when no OUTPUT_FILE is given the file lands in CWD\nORIG_DIR=\"$(pwd)\"\nWORK_DIR=\"${TEMP_DIR}/workspace\"\nmkdir -p \"$WORK_DIR\"\ncd \"$WORK_DIR\"\nassert_exit_code \\\n \"default output path (no output arg) exits 0\" \\\n 0 \\\n bash \"$GENERATOR\" standard\nif [[ -f \"${WORK_DIR}/standard-script.sh\" ]]; then\n pass \"default output file ./standard-script.sh was created\"\nelse\n fail \"default output file ./standard-script.sh was not created\"\nfi\n\nTRAVERSAL_TARGET=\"${TEMP_DIR}/templates/standard-script.sh\"\nrm -rf \"${TEMP_DIR}/templates\"\nassert_exit_code \\\n \"traversal payload with default output exits non-zero\" \\\n 1 \\\n bash \"$GENERATOR\" ../templates/standard\nif [[ ! -e \"$TRAVERSAL_TARGET\" ]]; then\n pass \"traversal payload did not create file outside current directory\"\nelse\n fail \"traversal payload created unexpected file: $TRAVERSAL_TARGET\"\nfi\ncd \"$ORIG_DIR\"\n\n# ─── log-analyzer.sh: argument handling ─────────────────────────────────────\n\necho \"\"\necho \"[log-analyzer.sh — argument handling]\"\n\nassert_exit_code \\\n \"no file arg exits non-zero\" \\\n 1 \\\n bash \"$LOG_ANALYZER\"\n\nassert_exit_code \\\n \"-h exits 0\" \\\n 0 \\\n bash \"$LOG_ANALYZER\" -h\n\nassert_exit_code \\\n \"nonexistent file exits non-zero\" \\\n 1 \\\n bash \"$LOG_ANALYZER\" /nonexistent/file.log\n\nassert_exit_code \\\n \"invalid report type exits non-zero\" \\\n 1 \\\n bash \"$LOG_ANALYZER\" -t badtype \"$LOG_FILE\"\n\n# ─── log-analyzer.sh: functional behaviour ──────────────────────────────────\n\necho \"\"\necho \"[log-analyzer.sh — functional behaviour]\"\n\nassert_exit_code \\\n \"summary report exits 0\" \\\n 0 \\\n bash \"$LOG_ANALYZER\" \"$LOG_FILE\"\n\nassert_output_contains \\\n \"summary report shows total lines\" \\\n \"Total lines\" \\\n bash \"$LOG_ANALYZER\" \"$LOG_FILE\"\n\nassert_output_contains \\\n \"summary shows ERROR count\" \\\n \"ERROR\" \\\n bash \"$LOG_ANALYZER\" \"$LOG_FILE\"\n\nassert_output_contains \\\n \"summary shows FATAL count\" \\\n \"FATAL\" \\\n bash \"$LOG_ANALYZER\" \"$LOG_FILE\"\n\nassert_exit_code \\\n \"errors report exits 0\" \\\n 0 \\\n bash \"$LOG_ANALYZER\" -t errors \"$LOG_FILE\"\n\nassert_output_contains \\\n \"errors report shows total errors\" \\\n \"Total errors\" \\\n bash \"$LOG_ANALYZER\" -t errors \"$LOG_FILE\"\n\n# Multi-word error messages must not be truncated\nassert_output_contains \\\n \"errors report preserves multi-word message (Connection refused to database)\" \\\n \"Connection refused to database\" \\\n bash \"$LOG_ANALYZER\" -t errors \"$LOG_FILE\"\n\nassert_output_contains \\\n \"errors report preserves multi-word message (Timeout on upstream request)\" \\\n \"Timeout on upstream request\" \\\n bash \"$LOG_ANALYZER\" -t errors \"$LOG_FILE\"\n\n# Repeated errors should show correct count (2 for \"Connection refused to database\")\nassert_output_contains \\\n \"errors report shows count 2 for repeated error\" \\\n \"Connection refused to database.*2\" \\\n bash \"$LOG_ANALYZER\" -t errors \"$LOG_FILE\"\n\n# Output to file\nREPORT=\"${TEMP_DIR}/report.txt\"\nassert_exit_code \\\n \"output-to-file exits 0\" \\\n 0 \\\n bash \"$LOG_ANALYZER\" -o \"$REPORT\" \"$LOG_FILE\"\n\nif [[ -f \"$REPORT\" ]]; then\n pass \"report file was created by -o flag\"\nelse\n fail \"report file was not created by -o flag\"\nfi\n\nassert_output_contains \\\n \"-o flag prints confirmation message to stdout\" \\\n \"Report saved to\" \\\n bash \"$LOG_ANALYZER\" -o \"${TEMP_DIR}/report2.txt\" \"$LOG_FILE\"\n\nassert_output_not_contains \\\n \"report file content excludes confirmation message\" \\\n \"Report saved to\" \\\n cat \"$REPORT\"\n\n# ─── run_ci_checks.sh: determinism and shellcheck gating ───────────────────\n\necho \"\"\necho \"[run_ci_checks.sh — deterministic validation]\"\n\nSHELLCHECK_STUB=\"${TEMP_DIR}/shellcheck-stub.sh\"\ncat > \"$SHELLCHECK_STUB\" \u003c\u003c'EOF'\n#!/usr/bin/env bash\nexit 0\nEOF\nchmod +x \"$SHELLCHECK_STUB\"\n\nassert_exit_code \\\n \"ci runner --help exits 0\" \\\n 0 \\\n bash \"$CI_RUNNER\" --help\n\nassert_exit_code \\\n \"ci runner succeeds when shellcheck is required and stubbed\" \\\n 0 \\\n env SHELLCHECK_BIN=\"$SHELLCHECK_STUB\" \\\n bash \"$CI_RUNNER\" --require-shellcheck --skip-regression-tests\n\nassert_exit_code \\\n \"ci runner fails when required shellcheck is unavailable\" \\\n 1 \\\n env SHELLCHECK_BIN=\"${TEMP_DIR}/missing-shellcheck\" \\\n bash \"$CI_RUNNER\" --require-shellcheck --skip-regression-tests\n\nassert_output_contains \\\n \"required-shellcheck failure message is explicit\" \\\n \"shellcheck is required but not available\" \\\n env SHELLCHECK_BIN=\"${TEMP_DIR}/missing-shellcheck\" \\\n bash \"$CI_RUNNER\" --require-shellcheck --skip-regression-tests\n\nassert_exit_code \\\n \"CI=true defaults to requiring shellcheck\" \\\n 1 \\\n env CI=true SHELLCHECK_BIN=\"${TEMP_DIR}/missing-shellcheck\" \\\n bash \"$CI_RUNNER\" --skip-regression-tests\n\n# ─── summary ────────────────────────────────────────────────────────────────\n\necho \"\"\necho \"Results: $PASS passed, $FAIL failed\"\necho \"\"\n\nif [[ $FAIL -gt 0 ]]; then\n exit 1\nfi\n","content_type":"application/x-sh; charset=utf-8","language":"bash","size":11790,"content_sha256":"8bea38a6876f35724dd11129b68d90a2811730c4e5cb987b6334dca84df82ad2"}],"content_json":{"type":"doc","content":[{"type":"heading","attrs":{"level":1},"content":[{"text":"Bash Script Generator","type":"text"}]},{"type":"heading","attrs":{"level":2},"content":[{"text":"Overview","type":"text"}]},{"type":"paragraph","content":[{"text":"Generate production-ready Bash scripts with clear requirements capture, deterministic generation flow, and validation-first iteration.","type":"text"}]},{"type":"heading","attrs":{"level":2},"content":[{"text":"Trigger Phrases","type":"text"}]},{"type":"paragraph","content":[{"text":"Use this skill when the user asks to:","type":"text"}]},{"type":"bullet_list","content":[{"type":"list_item","content":[{"type":"paragraph","content":[{"text":"Create, generate, write, or build a Bash/shell script","type":"text"}]}]},{"type":"list_item","content":[{"type":"paragraph","content":[{"text":"Convert manual CLI steps into an automation script","type":"text"}]}]},{"type":"list_item","content":[{"type":"paragraph","content":[{"text":"Build a text-processing script using ","type":"text"},{"text":"grep","type":"text","marks":[{"type":"code_inline"}]},{"text":", ","type":"text"},{"text":"awk","type":"text","marks":[{"type":"code_inline"}]},{"text":", or ","type":"text"},{"text":"sed","type":"text","marks":[{"type":"code_inline"}]}]}]},{"type":"list_item","content":[{"type":"paragraph","content":[{"text":"Create an operations helper script, cron script, or CI utility script","type":"text"}]}]}]},{"type":"paragraph","content":[{"text":"Do not use this skill for validating an existing script only. Use ","type":"text"},{"text":"devops-skills:bash-script-validator","type":"text","marks":[{"type":"code_inline"}]},{"text":" for validation-only requests.","type":"text"}]},{"type":"heading","attrs":{"level":2},"content":[{"text":"Execution Model","type":"text"}]},{"type":"paragraph","content":[{"text":"Follow stages in order. Do not skip a stage; use the documented fallback when blocked.","type":"text"}]},{"type":"heading","attrs":{"level":3},"content":[{"text":"Stage 0: Preflight","type":"text"}]},{"type":"ordered_list","attrs":{"order":1,"listStyle":"number"},"content":[{"type":"list_item","content":[{"type":"paragraph","content":[{"text":"Confirm scope and target output path.","type":"text"}]}]},{"type":"list_item","content":[{"type":"paragraph","content":[{"text":"Confirm shell target:","type":"text"}]}]}]},{"type":"bullet_list","content":[{"type":"list_item","content":[{"type":"paragraph","content":[{"text":"Default: ","type":"text"},{"text":"bash","type":"text","marks":[{"type":"code_inline"}]}]}]},{"type":"list_item","content":[{"type":"paragraph","content":[{"text":"If portability is requested: POSIX ","type":"text"},{"text":"sh","type":"text","marks":[{"type":"code_inline"}]}]}]}]},{"type":"ordered_list","attrs":{"order":3,"listStyle":"number"},"content":[{"type":"list_item","content":[{"type":"paragraph","content":[{"text":"Check capabilities and pick fallback path:","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":"Capability","type":"text"}]}]},{"type":"th","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"Default Path","type":"text"}]}]},{"type":"th","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"Fallback Path","type":"text"}]}]}]},{"type":"tr","content":[{"type":"td","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"Requirement clarification","type":"text"}]}]},{"type":"td","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"AskUserQuestion tool","type":"text"}]}]},{"type":"td","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"Ask same questions in normal chat; mark unresolved items as assumptions","type":"text"}]}]}]},{"type":"tr","content":[{"type":"td","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"Script scaffold","type":"text"}]}]},{"type":"td","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"bash scripts/generate_script_template.sh ...","type":"text","marks":[{"type":"code_inline"}]}]}]},{"type":"td","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"Copy ","type":"text"},{"text":"assets/templates/standard-template.sh","type":"text","marks":[{"type":"code_inline"}]},{"text":" manually or hand-craft minimal scaffold","type":"text"}]}]}]},{"type":"tr","content":[{"type":"td","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"Validation","type":"text"}]}]},{"type":"td","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"devops-skills:bash-script-validator","type":"text","marks":[{"type":"code_inline"}]}]}]},{"type":"td","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"Local checks: ","type":"text"},{"text":"bash -n","type":"text","marks":[{"type":"code_inline"}]},{"text":", ","type":"text"},{"text":"shellcheck","type":"text","marks":[{"type":"code_inline"}]},{"text":" if available, ","type":"text"},{"text":"sh -n","type":"text","marks":[{"type":"code_inline"}]},{"text":" for POSIX mode","type":"text"}]}]}]}]},{"type":"paragraph","content":[{"text":"If a fallback path is used, state it explicitly in the final summary.","type":"text"}]},{"type":"heading","attrs":{"level":3},"content":[{"text":"Stage 1: Capture Requirements","type":"text"}]},{"type":"paragraph","content":[{"text":"Collect only what is needed to generate the script correctly:","type":"text"}]},{"type":"bullet_list","content":[{"type":"list_item","content":[{"type":"paragraph","content":[{"text":"Input source and format","type":"text"}]}]},{"type":"list_item","content":[{"type":"paragraph","content":[{"text":"Output destination and format","type":"text"}]}]},{"type":"list_item","content":[{"type":"paragraph","content":[{"text":"Error handling behavior (fail-fast/retry/continue)","type":"text"}]}]},{"type":"list_item","content":[{"type":"paragraph","content":[{"text":"Security constraints (sensitive data, privilege level)","type":"text"}]}]},{"type":"list_item","content":[{"type":"paragraph","content":[{"text":"Performance constraints (large files, parallelism)","type":"text"}]}]},{"type":"list_item","content":[{"type":"paragraph","content":[{"text":"Portability requirement (Bash-only vs POSIX)","type":"text"}]}]}]},{"type":"paragraph","content":[{"text":"Then create a ","type":"text"},{"text":"Captured Requirements","type":"text","marks":[{"type":"code_inline"}]},{"text":" table with stable IDs.","type":"text"}]},{"type":"code_block","attrs":{"wrap":false,"language":"markdown"},"content":[{"text":"## Captured Requirements\n\n| Requirement ID | Description | Source | Implementation Plan |\n|---|---|---|---|\n| REQ-001 | Parse nginx logs from file input | User | `parse_args()` + `validate_file()` + `awk` parser |\n| REQ-002 | Output top 10 errors | User | `analyze_errors()` + `sort | uniq -c | head -10` |\n| REQ-003 | Handle large files efficiently | Assumption | Single-pass `awk`; avoid multi-pass loops |","type":"text"}]},{"type":"paragraph","content":[{"text":"Rules:","type":"text"}]},{"type":"bullet_list","content":[{"type":"list_item","content":[{"type":"paragraph","content":[{"text":"Every major design decision maps to at least one ","type":"text"},{"text":"REQ-*","type":"text","marks":[{"type":"code_inline"}]},{"text":".","type":"text"}]}]},{"type":"list_item","content":[{"type":"paragraph","content":[{"text":"Keep assumptions explicit and minimal.","type":"text"}]}]}]},{"type":"heading","attrs":{"level":3},"content":[{"text":"Stage 2: Choose Generation Path","type":"text"}]},{"type":"paragraph","content":[{"text":"Use this deterministic decision tree:","type":"text"}]},{"type":"code_block","attrs":{"wrap":false,"language":"text"},"content":[{"text":"Need multi-command architecture, unusual control flow, or strict non-template conventions?\n├─ Yes -> Custom generation\n└─ No\n Need standard CLI skeleton (usage/logging/arg parsing/cleanup)?\n ├─ Yes -> Template-first generation\n └─ No -> Custom generation","type":"text"}]},{"type":"paragraph","content":[{"text":"Template-first is the default for single-purpose CLI utilities.","type":"text"}]},{"type":"heading","attrs":{"level":3},"content":[{"text":"Stage 3: Load Only Relevant References","type":"text"}]},{"type":"paragraph","content":[{"text":"Use progressive disclosure. Read only docs needed for the current request.","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","type":"text"}]}]},{"type":"th","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"Reference","type":"text"}]}]}]},{"type":"tr","content":[{"type":"td","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"Tool choice (","type":"text"},{"text":"grep","type":"text","marks":[{"type":"code_inline"}]},{"text":" vs ","type":"text"},{"text":"awk","type":"text","marks":[{"type":"code_inline"}]},{"text":" vs ","type":"text"},{"text":"sed","type":"text","marks":[{"type":"code_inline"}]},{"text":")","type":"text"}]}]},{"type":"td","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"docs/text-processing-guide.md","type":"text","marks":[{"type":"code_inline"}]}]}]}]},{"type":"tr","content":[{"type":"td","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"Script structure and argument patterns","type":"text"}]}]},{"type":"td","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"docs/script-patterns.md","type":"text","marks":[{"type":"code_inline"}]}]}]}]},{"type":"tr","content":[{"type":"td","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"Strict mode, shell differences, safety","type":"text"}]}]},{"type":"td","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"docs/bash-scripting-guide.md","type":"text","marks":[{"type":"code_inline"}]}]}]}]},{"type":"tr","content":[{"type":"td","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"Naming, organization, and quality baseline","type":"text"}]}]},{"type":"td","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"docs/generation-best-practices.md","type":"text","marks":[{"type":"code_inline"}]}]}]}]}]},{"type":"paragraph","content":[{"text":"Citation format (required):","type":"text"}]},{"type":"bullet_list","content":[{"type":"list_item","content":[{"type":"paragraph","content":[{"text":"[Ref: docs/\u003cfile>.md -> \u003csection>]","type":"text","marks":[{"type":"code_inline"}]}]}]}]},{"type":"heading","attrs":{"level":3},"content":[{"text":"Stage 4: Generate Script","type":"text"}]},{"type":"heading","attrs":{"level":4},"content":[{"text":"Path A: Template-first (default)","type":"text"}]},{"type":"ordered_list","attrs":{"order":1,"listStyle":"number"},"content":[{"type":"list_item","content":[{"type":"paragraph","content":[{"text":"Generate scaffold:","type":"text"}]}]}]},{"type":"code_block","attrs":{"wrap":false,"language":"bash"},"content":[{"text":"bash scripts/generate_script_template.sh standard output-script.sh","type":"text"}]},{"type":"ordered_list","attrs":{"order":2,"listStyle":"number"},"content":[{"type":"list_item","content":[{"type":"paragraph","content":[{"text":"Replace placeholders and add business logic.","type":"text"}]}]},{"type":"list_item","content":[{"type":"paragraph","content":[{"text":"Keep logging to stderr and data output to stdout unless requirements say otherwise.","type":"text"}]}]},{"type":"list_item","content":[{"type":"paragraph","content":[{"text":"Add comments only where logic is non-obvious.","type":"text"}]}]}]},{"type":"heading","attrs":{"level":4},"content":[{"text":"Path B: Custom generation","type":"text"}]},{"type":"paragraph","content":[{"text":"Build a script with at least:","type":"text"}]},{"type":"bullet_list","content":[{"type":"list_item","content":[{"type":"paragraph","content":[{"text":"Shebang and strict mode","type":"text"}]}]},{"type":"list_item","content":[{"type":"paragraph","content":[{"text":"usage()","type":"text","marks":[{"type":"code_inline"}]}]}]},{"type":"list_item","content":[{"type":"paragraph","content":[{"text":"parse_args()","type":"text","marks":[{"type":"code_inline"}]}]}]},{"type":"list_item","content":[{"type":"paragraph","content":[{"text":"Input validation and dependency checks","type":"text"}]}]},{"type":"list_item","content":[{"type":"paragraph","content":[{"text":"Main workflow function(s)","type":"text"}]}]},{"type":"list_item","content":[{"type":"paragraph","content":[{"text":"Predictable exit codes","type":"text"}]}]}]},{"type":"heading","attrs":{"level":3},"content":[{"text":"Stage 5: Validate and Iterate","type":"text"}]},{"type":"paragraph","content":[{"text":"Default validation path:","type":"text"}]},{"type":"ordered_list","attrs":{"order":1,"listStyle":"number"},"content":[{"type":"list_item","content":[{"type":"paragraph","content":[{"text":"Invoke ","type":"text"},{"text":"devops-skills:bash-script-validator","type":"text","marks":[{"type":"code_inline"}]}]}]},{"type":"list_item","content":[{"type":"paragraph","content":[{"text":"Apply fixes","type":"text"}]}]},{"type":"list_item","content":[{"type":"paragraph","content":[{"text":"Re-run validation","type":"text"}]}]},{"type":"list_item","content":[{"type":"paragraph","content":[{"text":"Repeat until checks pass or blocker is identified","type":"text"}]}]}]},{"type":"paragraph","content":[{"text":"Fallback validation path (when validator skill is unavailable):","type":"text"}]},{"type":"code_block","attrs":{"wrap":false,"language":"bash"},"content":[{"text":"# Deterministic local gate for this skill:\nbash scripts/run_ci_checks.sh --skip-shellcheck\n\n# CI gate (shellcheck required):\nbash scripts/run_ci_checks.sh --require-shellcheck","type":"text"}]},{"type":"paragraph","content":[{"text":"If any check is skipped, include ","type":"text"},{"text":"Skipped check","type":"text","marks":[{"type":"code_inline"}]},{"text":", ","type":"text"},{"text":"Reason","type":"text","marks":[{"type":"code_inline"}]},{"text":", and ","type":"text"},{"text":"Risk","type":"text","marks":[{"type":"code_inline"}]},{"text":" in the output.","type":"text"}]},{"type":"heading","attrs":{"level":3},"content":[{"text":"Stage 6: Final Response Contract","type":"text"}]},{"type":"paragraph","content":[{"text":"Always return:","type":"text"}]},{"type":"ordered_list","attrs":{"order":1,"listStyle":"number"},"content":[{"type":"list_item","content":[{"type":"paragraph","content":[{"text":"Generated script path","type":"text"}]}]},{"type":"list_item","content":[{"type":"paragraph","content":[{"text":"Requirements traceability (","type":"text"},{"text":"REQ-*","type":"text","marks":[{"type":"code_inline"}]},{"text":" -> implementation)","type":"text"}]}]},{"type":"list_item","content":[{"type":"paragraph","content":[{"text":"Validation results with rerun status","type":"text"}]}]},{"type":"list_item","content":[{"type":"paragraph","content":[{"text":"Citations in standard format","type":"text"}]}]},{"type":"list_item","content":[{"type":"paragraph","content":[{"text":"Any assumptions/fallbacks used","type":"text"}]}]}]},{"type":"heading","attrs":{"level":2},"content":[{"text":"Canonical Example Flows","type":"text"}]},{"type":"heading","attrs":{"level":3},"content":[{"text":"Example A: Full Flow (Template-first)","type":"text"}]},{"type":"ordered_list","attrs":{"order":1,"listStyle":"number"},"content":[{"type":"list_item","content":[{"type":"paragraph","content":[{"text":"Clarify missing data format and output expectations.","type":"text"}]}]},{"type":"list_item","content":[{"type":"paragraph","content":[{"text":"Capture ","type":"text"},{"text":"REQ-*","type":"text","marks":[{"type":"code_inline"}]},{"text":" table.","type":"text"}]}]},{"type":"list_item","content":[{"type":"paragraph","content":[{"text":"Choose template-first path.","type":"text"}]}]},{"type":"list_item","content":[{"type":"paragraph","content":[{"text":"Generate scaffold with ","type":"text"},{"text":"scripts/generate_script_template.sh","type":"text","marks":[{"type":"code_inline"}]},{"text":".","type":"text"}]}]},{"type":"list_item","content":[{"type":"paragraph","content":[{"text":"Implement logic and map functions to ","type":"text"},{"text":"REQ-*","type":"text","marks":[{"type":"code_inline"}]},{"text":".","type":"text"}]}]},{"type":"list_item","content":[{"type":"paragraph","content":[{"text":"Validate with ","type":"text"},{"text":"devops-skills:bash-script-validator","type":"text","marks":[{"type":"code_inline"}]},{"text":" and rerun until clean.","type":"text"}]}]},{"type":"list_item","content":[{"type":"paragraph","content":[{"text":"Return final summary with citations.","type":"text"}]}]}]},{"type":"heading","attrs":{"level":3},"content":[{"text":"Example B: Constrained Environment Flow","type":"text"}]},{"type":"paragraph","content":[{"text":"Use this when AskUserQuestion, validator skill, or ","type":"text"},{"text":"shellcheck","type":"text","marks":[{"type":"code_inline"}]},{"text":" is unavailable:","type":"text"}]},{"type":"ordered_list","attrs":{"order":1,"listStyle":"number"},"content":[{"type":"list_item","content":[{"type":"paragraph","content":[{"text":"Ask clarifying questions in chat.","type":"text"}]}]},{"type":"list_item","content":[{"type":"paragraph","content":[{"text":"Mark unresolved items as assumptions in ","type":"text"},{"text":"Captured Requirements","type":"text","marks":[{"type":"code_inline"}]},{"text":".","type":"text"}]}]},{"type":"list_item","content":[{"type":"paragraph","content":[{"text":"Generate from template script or template file copy fallback.","type":"text"}]}]},{"type":"list_item","content":[{"type":"paragraph","content":[{"text":"Run ","type":"text"},{"text":"bash -n","type":"text","marks":[{"type":"code_inline"}]},{"text":" (and ","type":"text"},{"text":"sh -n","type":"text","marks":[{"type":"code_inline"}]},{"text":" if relevant).","type":"text"}]}]},{"type":"list_item","content":[{"type":"paragraph","content":[{"text":"If ","type":"text"},{"text":"shellcheck","type":"text","marks":[{"type":"code_inline"}]},{"text":" is missing, report skip with risk and mitigation.","type":"text"}]}]}]},{"type":"heading","attrs":{"level":2},"content":[{"text":"Done Criteria","type":"text"}]},{"type":"paragraph","content":[{"text":"The task is complete only when all items are true:","type":"text"}]},{"type":"bullet_list","content":[{"type":"list_item","content":[{"type":"paragraph","content":[{"text":"Trigger matched and scope confirmed","type":"text"}]}]},{"type":"list_item","content":[{"type":"paragraph","content":[{"text":"Captured Requirements","type":"text","marks":[{"type":"code_inline"}]},{"text":" table exists with ","type":"text"},{"text":"REQ-*","type":"text","marks":[{"type":"code_inline"}]},{"text":" IDs","type":"text"}]}]},{"type":"list_item","content":[{"type":"paragraph","content":[{"text":"Template-first vs custom decision is documented","type":"text"}]}]},{"type":"list_item","content":[{"type":"paragraph","content":[{"text":"Script is generated with deterministic structure","type":"text"}]}]},{"type":"list_item","content":[{"type":"paragraph","content":[{"text":"Validation executed and rerun policy applied","type":"text"}]}]},{"type":"list_item","content":[{"type":"paragraph","content":[{"text":"Any skipped checks include explicit reason and risk","type":"text"}]}]},{"type":"list_item","content":[{"type":"paragraph","content":[{"text":"Final response includes traceability, citations, and assumptions","type":"text"}]}]}]},{"type":"heading","attrs":{"level":2},"content":[{"text":"Helper Scripts and Assets","type":"text"}]},{"type":"bullet_list","content":[{"type":"list_item","content":[{"type":"paragraph","content":[{"text":"Script generator: ","type":"text"},{"text":"scripts/generate_script_template.sh","type":"text","marks":[{"type":"code_inline"}]}]}]},{"type":"list_item","content":[{"type":"paragraph","content":[{"text":"Deterministic CI gate: ","type":"text"},{"text":"scripts/run_ci_checks.sh","type":"text","marks":[{"type":"code_inline"}]}]}]},{"type":"list_item","content":[{"type":"paragraph","content":[{"text":"Regression test suite: ","type":"text"},{"text":"scripts/test_generator.sh","type":"text","marks":[{"type":"code_inline"}]}]}]},{"type":"list_item","content":[{"type":"paragraph","content":[{"text":"Standard scaffold: ","type":"text"},{"text":"assets/templates/standard-template.sh","type":"text","marks":[{"type":"code_inline"}]}]}]},{"type":"list_item","content":[{"type":"paragraph","content":[{"text":"Example output style: ","type":"text"},{"text":"examples/log-analyzer.sh","type":"text","marks":[{"type":"code_inline"}]}]}]}]},{"type":"heading","attrs":{"level":2},"content":[{"text":"Reference Docs","type":"text"}]},{"type":"bullet_list","content":[{"type":"list_item","content":[{"type":"paragraph","content":[{"text":"docs/bash-scripting-guide.md","type":"text","marks":[{"type":"code_inline"}]}]}]},{"type":"list_item","content":[{"type":"paragraph","content":[{"text":"docs/script-patterns.md","type":"text","marks":[{"type":"code_inline"}]}]}]},{"type":"list_item","content":[{"type":"paragraph","content":[{"text":"docs/generation-best-practices.md","type":"text","marks":[{"type":"code_inline"}]}]}]},{"type":"list_item","content":[{"type":"paragraph","content":[{"text":"docs/text-processing-guide.md","type":"text","marks":[{"type":"code_inline"}]}]}]}]},{"type":"heading","attrs":{"level":2},"content":[{"text":"External References","type":"text"}]},{"type":"bullet_list","content":[{"type":"list_item","content":[{"type":"paragraph","content":[{"text":"GNU Bash Manual","type":"text","marks":[{"type":"link","attrs":{"href":"https://www.gnu.org/software/bash/manual/bash.html","title":null}}]}]}]},{"type":"list_item","content":[{"type":"paragraph","content":[{"text":"POSIX Shell Specification","type":"text","marks":[{"type":"link","attrs":{"href":"https://pubs.opengroup.org/onlinepubs/9699919799/","title":null}}]}]}]},{"type":"list_item","content":[{"type":"paragraph","content":[{"text":"ShellCheck","type":"text","marks":[{"type":"link","attrs":{"href":"https://www.shellcheck.net/","title":null}}]}]}]}]}]},"metadata":{"date":"2026-11-02","name":"bash-script-generator","author":"@skillopedia","source":{"stars":331,"repo_name":"cc-devops-skills","origin_url":"https://github.com/akin-ozer/cc-devops-skills/blob/HEAD/devops-skills-plugin/skills/bash-script-generator/SKILL.md","repo_owner":"akin-ozer","body_sha256":"b47b1523883f16e171bfef13efa34ee0786b6e2225ef6f5e91b5bd726d43d4ab","cluster_key":"50de2c71233dac953b59ea29aa9e92d5e6dc23f0cc5a3caa869badc6dcea5bc9","clean_bundle":{"format":"clean-skill-bundle-v1","source":"akin-ozer/cc-devops-skills/devops-skills-plugin/skills/bash-script-generator/SKILL.md","text_bytes":64016,"source_commit":"276af751e659315aaf56d3ad13d7c26f4e72e28a","skills_sh_rank":16290,"attachment_count":9,"text_attachments":9,"attachment_storage":"skill_attachments","binary_attachments":0},"cluster_size":1,"skill_md_path":"devops-skills-plugin/skills/bash-script-generator/SKILL.md","import_metadata":{"date":"2026-11-02","author":"@skillopedia","version":"v1","category":"software-engineering","category_label":"Engineering"},"exact_dupes_collapsed_into_this":0},"version":"v1","category":"software-engineering","import_tag":"skills-sh-top20k-2026-11","description":"Create, generate, write, or scaffold bash/shell scripts (.sh), automation, or CLI tools."}},"renderedAt":1793671037908}

Bash Script Generator Overview Generate production-ready Bash scripts with clear requirements capture, deterministic generation flow, and validation-first iteration. Trigger Phrases Use this skill when the user asks to: - Create, generate, write, or build a Bash/shell script - Convert manual CLI steps into an automation script - Build a text-processing script using , , or - Create an operations helper script, cron script, or CI utility script Do not use this skill for validating an existing script only. Use for validation-only requests. Execution Model Follow stages in order. Do not skip a st…