Bash Script Generator
Overview
This skill generates production-ready bash scripts with best practices built-in: strict mode, error handling, logging, argument parsing, input validation, and cleanup traps. Use for system administration, text processing, API clients, automation workflows, and scheduled tasks.
Pre-Generation Checklist (REQUIRED)
Before writing any script, complete these steps:
Clarify ambiguities — ask if any of the following are unclear:
- Input data format (nginx log, JSON, CSV, custom?)
- Large file handling (>100MB)?
- Error handling preference (fail fast / continue / retry)?
- Security context (sensitive data, elevated privileges)?
- Portability needs (bash-specific vs POSIX sh)?
- Output format (human-readable, JSON, CSV)?
Explain your approach — before writing code, briefly describe:
- Script architecture and main functions
- Tool selections (grep/awk/sed) with rationale from
references/text-processing-guide.md - Key design decisions and customization points
Use the template for standard scripts (CLI tools, automation scripts):
bash scripts/generate_script_template.sh standard output-script.shThen customize for your specific use case.
Generation Workflow
Stage 1 – Understand Requirements
Determine: purpose, input/output sources, bash vs POSIX sh, argument needs, error handling strategy, performance constraints, security requirements. Use AskUserQuestion for anything unclear.
Stage 2 – Architecture Planning
- Select functions, config management, logging strategy, error handling approach
- Tool selection: grep (pattern matching/filtering), awk (structured data, calculations), sed (substitutions, stream editing), find (filesystem), curl/wget (HTTP)
- Plan
set -euo pipefail, error functions, andtrapcleanup
Stage 3 – Script Structure
#!/usr/bin/env bash
#
# Script Name: script-name.sh
# Description: Brief description
# Created: YYYY-MM-DD
#
set -euo pipefail
IFS=$'\n\t'
readonly SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
readonly SCRIPT_NAME="$(basename "${BASH_SOURCE[0]}")"
cleanup() {
local exit_code=$?
# Remove temp files, release locks, etc.
exit "${exit_code}"
}
trap cleanup EXIT ERR INT TERM
Stage 4 – Core Functions
Full implementations are in assets/templates/standard-template.sh. Key signatures to include:
Logging (one line per level):
log_info() { echo "[INFO] $(date '+%Y-%m-%d %H:%M:%S') - $*" >&2; }
log_warn() { echo "[WARN] $(date '+%Y-%m-%d %H:%M:%S') - $*" >&2; }
log_error() { echo "[ERROR] $(date '+%Y-%m-%d %H:%M:%S') - $*" >&2; }
log_fatal() { echo "[FATAL] $(date '+%Y-%m-%d %H:%M:%S') - $*" >&2; exit 1; }
# Add log_debug with LOG_LEVEL guard from template when DEBUG support is needed
Error handling:
die() { log_error "$@"; exit 1; }
check_command() { command -v "$1" &>/dev/null || die "Required command '$1' not found."; }
validate_file() { [[ -f "$1" ]] || die "File not found: $1"; [[ -r "$1" ]] || die "File not readable: $1"; }
Argument parsing (getopts):
usage() {
cat << EOF
Usage: ${SCRIPT_NAME} [OPTIONS] [ARGUMENTS]
Options:
-h Show this help and exit
-v Enable verbose output
-f FILE Input file path
-o FILE Output file path
-d Enable debug logging
Examples:
${SCRIPT_NAME} -f input.txt -o output.txt
EOF
}
parse_args() {
while getopts ":hvf:o:d" opt; do
case ${opt} in
h) usage; exit 0 ;;
v) VERBOSE=true ;;
f) INPUT_FILE="${OPTARG}" ;;
o) OUTPUT_FILE="${OPTARG}" ;;
d) LOG_LEVEL="DEBUG" ;;
\?) echo "Invalid option: -${OPTARG}" >&2; usage; exit 1 ;;
:) echo "Option -${OPTARG} requires an argument" >&2; usage; exit 1 ;;
esac
done
shift $((OPTIND - 1))
}
Stage 5 – Business Logic
- Text processing: use
references/text-processing-guide.mdfor grep/awk/sed selection - System administration: include prerequisite validation, backup, rollback, progress indicators
- API clients: include HTTP error handling, retry logic, authentication, response parsing
Stage 6 – Main Function
main() {
parse_args "$@" # From Stage 4
check_command "grep"
check_command "awk"
[[ -n "${INPUT_FILE:-}" ]] || die "Input file not specified. Use -f option."
validate_file "${INPUT_FILE}"
log_info "Starting processing..." # From Stage 4
# Main logic here
log_info "Processing completed successfully"
}
main "$@"
Stage 7 – Documentation
#######################################
# Brief description of function
# Globals:
# VARIABLE_NAME
# Arguments:
# $1 - Description
# Outputs:
# Writes results to stdout
# Returns:
# 0 if successful, non-zero on error
#######################################
Stage 8 – Validate
After generating any script, invoke devops-skills:bash-script-validator:
- Generate the script
- Run validator; review syntax, ShellCheck, security, performance results
- Fix issues and re-validate until all checks pass
- Provide Post-Generation Summary (see below)
Key Best Practices
Security:
- Always quote variables:
"${var}"not$var - Validate inputs:
[[ "${val}" =~ ^[a-zA-Z0-9/_.-]+$ ]] || die "Invalid" - Never
evaluser input; usecasestatements instead
Performance:
- Avoid useless
cat:grep pattern filenotcat file | grep pattern - Single-pass awk:
awk '/ERROR/{e++} /WARN/{w++} END{print e,w}' log
Maintainability:
- Functions follow single responsibility
- Use
readonlyfor constants - Meaningful variable names; comments for complex logic
Portability (POSIX sh):
- Avoid bash arrays,
[[ ]],$BASH_SOURCE; test withsh -n script.sh
Common Script Patterns
See references/script-patterns.md for full templates including text processing and parallel batch processing. Quick reference for simple CLI tools:
Pattern 1 – Simple CLI tool:
#!/usr/bin/env bash
set -euo pipefail
# For production scripts, use the full logging and argument parsing
# functions from Stage 4 above. This minimal example demonstrates structure:
usage() { cat << EOF
Usage: ${0##*/} [OPTIONS] FILE
-h Show help
-v Verbose
-o Output file
EOF
}
main() {
local verbose=false output_file="" input_file=""
while getopts ":hvo:" opt; do
case ${opt} in
h) usage; exit 0 ;; v) verbose=true ;; o) output_file="${OPTARG}" ;;
*) echo "Invalid option: -${OPTARG}" >&2; usage; exit 1 ;;
esac
done
shift $((OPTIND - 1))
input_file="${1:-}"
[[ -n "${input_file}" ]] || { echo "Error: FILE required" >&2; usage; exit 1; }
[[ -f "${input_file}" ]] || { echo "Error: File not found: ${input_file}" >&2; exit 1; }
if [[ -n "${output_file}" ]]; then
process_file "${input_file}" > "${output_file}"
else
process_file "${input_file}"
fi
}
process_file() { local file="$1"; cat "${file}"; }
main "$@"
For text processing (grep/awk/sed pipelines) and parallel batch processing patterns, see references/script-patterns.md.
Post-Generation Summary (REQUIRED)
After every script, provide:
## Generated Script Summary
**File:** path/to/script.sh
**Architecture:** [main functions and purposes]
**Tool Selection:**
- grep: [why used]
- awk: [why used]
- sed: [why used / not needed]
**Key Features:** [list]
**Customization Points:** [variables/functions to modify]
**Usage:**
./script.sh --help
./script.sh -v input.log
**Validation Status:** ✅ Passed ShellCheck / ❌ Issues found (fixing...)
**Documentation References:**
- references/text-processing-guide.md (tool selection)
- references/script-patterns.md (argument parsing)
Anti-Patterns
NEVER start a bash script without set -euo pipefail
- WHY: Without these flags, errors are silently ignored:
-ecauses exit on error,-uerrors on unset variables,-o pipefailcatches pipeline failures. - BAD:
#!/usr/bin/env bashwith no error flags and silent failures. - GOOD:
#!/usr/bin/env bashfollowed immediately byset -euo pipefailas the first two lines of every script.
NEVER use unquoted variable expansions in command arguments
- WHY: Word splitting and glob expansion on unquoted
$VARcause subtle bugs when values contain spaces or special characters. - BAD:
cp $SOURCE $DEST - GOOD:
cp "$SOURCE" "$DEST"
NEVER use ls | grep to filter files
- WHY:
lsoutput is not reliably parseable; it is locale-dependent and breaks on filenames with special characters. - BAD:
ls *.log | grep error - GOOD:
for f in *.log; do grep error "$f"; doneorfind . -name "*.log" -exec grep error {} +
NEVER hardcode absolute paths for tools like python, node, or bash
- WHY: Paths differ across operating systems and distributions, making scripts non-portable.
- BAD:
#!/usr/bin/python3or/usr/local/bin/node script.js - GOOD: Use
#!/usr/bin/env python3, rely on PATH fornode script.js, or guard withcommand -v python3 || { echo "python3 required"; exit 1; }.
NEVER use eval to execute dynamically constructed commands
- WHY:
evalenables code injection when any part of the command comes from user input or external data. - BAD:
eval "rm -rf $USER_INPUT" - GOOD: Use arrays for command construction:
cmd=(rm -rf "$USER_INPUT"); "${cmd[@]}"
References
Internal references (offline, load as context):
references/bash-scripting-guide.md— strict mode, functions, arrays, parameter expansionreferences/script-patterns.md— argument parsing, logging, retry logic, lock files, parallel processingreferences/text-processing-guide.md— grep/awk/sed selection, pipelines, large-file optimizationreferences/generation-best-practices.md— naming, documentation, testing, security, portabilityassets/templates/standard-template.sh— production-ready template with all componentsexamples/log-analyzer.sh— grep/awk/sed usage demonstrationscripts/generate_script_template.sh— template generator tool
Official documentation:
All generated scripts are automatically validated using devops-skills:bash-script-validator to ensure correct syntax, ShellCheck compliance, security, and performance.