Structured Bash Script Generator
What You'll Do
- •📥 Gather the script's goal, required positional/flag arguments, environment variables, and external program dependencies
- •🧱 Produce a Bash 3.2-compatible script skeleton with a
check_requirementsfunction that validates inputs and dependencies kindly - •🛡️ Ensure the script sets safe defaults (
set -euo pipefail), quotes expansions, and keeps logic portable to macOS/Linux Bash 3.2 - •✨ Format the script with
shfmtwhen available and return a polished result ready for immediate use
When to Use This Skill
Use this skill whenever the user asks for a new bash script or a major refactor of an existing script and they expect:
- •Guardrails around required arguments, environment variables, or external tools
- •Friendly, actionable error messages when prerequisites are missing
- •Compatibility with older Bash versions (macOS default 3.2)
Do not use this skill for:
- •POSIX
sh-only scripts (no Bash-specific features allowed) - •Small one-liners or trivial command snippets (respond inline instead)
- •Advanced Bash (>3.2) needs such as associative arrays or
coproc
Phase 1 · Clarify the Script Brief
- •Confirm the script's purpose, expected inputs, outputs, and typical usage examples.
- •Identify all positional arguments and flags that must be provided. Capture human-friendly labels for each so the usage text and errors are clear.
- •List required environment variables (names + meaning) and external commands (e.g.,
curl,jq). Note install hints when useful. - •Ask about optional inputs or defaults that should be applied when values are omitted.
- •Determine whether the script writes files, consumes stdin/stdout, or needs cleanup logic.
Deliverable: A short table (in notes or your head) of arguments, env vars, and commands you will feed into
check_requirementsandusagemessaging.
Phase 2 · Plan the Script Structure
Lay out the sections before writing code:
- •
Header & Safety
- •
#!/usr/bin/env bash - •
set -euo pipefail - •
IFS=$'\n\t'only if tighter word splitting is needed.
- •
- •
Metadata Comments (optional)
- •Summarize script purpose and prerequisites in commented lines for discoverability.
- •
Usage Helper
- •A
usage()function that prints how to run the script, expected args, environment variables, and examples.
- •A
- •
Requirement Configuration
- •Define
REQUIRED_ARGS,REQUIRED_ENV_VARS, andREQUIRED_PROGRAMSas indexed arrays (compatible with Bash 3.2). When nothing is required, keep the arrays empty but present. - •Optionally define associative-looking notes via comments or simple
casestatements; do not usedeclare -A(requires Bash ≥4).
- •Define
- •
check_requirements Function (see Phase 3 for exact pattern)
- •Accepts parsed arguments (or a struct) and validates all prerequisites.
- •Emits kind, actionable errors to STDERR and returns non-zero on failure.
- •
Argument Parsing
- •Prefer
getoptsfor short flags. For long options, parse manually with awhileloop; avoidgetoptif portability is uncertain. - •Populate variables for downstream logic (use
${VAR:-}to coexist withset -u).
- •Prefer
- •
Main Logic
- •Encapsulate primary workflow in
main()and finish withmain "$@".
- •Encapsulate primary workflow in
Phase 3 · Compose the Script
Follow this recipe while writing the actual script content.
Required Guardrail: check_requirements
check_requirements() {
local -r provided_arg_count=$1
local missing=0
if [ ${#REQUIRED_ARGS[@]} -gt 0 ] && [ "$provided_arg_count" -lt ${#REQUIRED_ARGS[@]} ]; then
printf 'Error: Expected %s arguments (%s) but received %s.\n' \
${#REQUIRED_ARGS[@]} "${REQUIRED_ARGS[*]}" "$provided_arg_count" >&2
missing=1
fi
local env_var
for env_var in "${REQUIRED_ENV_VARS[@]}"; do
if [ -z "${!env_var:-}" ]; then
printf 'Error: Missing required environment variable %s. Please set it before rerunning.\n' "$env_var" >&2
missing=1
fi
done
local program
for program in "${REQUIRED_PROGRAMS[@]}"; do
if ! command -v "$program" >/dev/null 2>&1; then
printf 'Error: Required program %s is not installed or not on PATH. Please install it first.\n' "$program" >&2
missing=1
fi
done
if [ "$missing" -ne 0 ]; then
printf '\n' >&2
usage >&2
return 1
fi
}
Implementation notes:
- •Always invoke
check_requirementsright after argument parsing, e.g.check_requirements "$#". - •If the script allows optional trailing arguments, keep
REQUIRED_ARGSlimited to the mandatory ones and validate optional parameters separately aftercheck_requirements "$#"succeeds. - •Keep error language supportive (“Please install…”) rather than punitive.
- •Route any diagnostics to STDERR (
>&2) and exit gracefully withreturn 1so the caller canexit 1or handle it. - •Only call
usagefrom error paths (like failed requirement checks) so successful runs stay quiet unless the user explicitly asks for help.
Bash 3.2 Compatibility Guardrails
- •Use indexed arrays only; no associative arrays or namerefs (
local -n). - •Avoid
[[ string =~ regex ]]with capture groups that rely on Bash ≥3.2. Basic regex is fine, but keep patterns simple. - •Do not rely on
mapfile,readarray,coproc,printf -v, or process substitution that requires/dev/fd(often missing on macOS). - •Prefer
$( command )subshells over backticks and quote every expansion. - •Use
printfinstead ofecho -efor reliable escape handling.
Usage Function Pattern
usage() {
cat <<'EOF'
Usage: my_script.sh <source> <destination> [--dry-run]
Required arguments:
source Path to the input file (must exist)
destination Output directory (will be created if missing)
Environment variables:
API_TOKEN Token used to authenticate API requests
External tools:
curl, jq
Examples:
my_script.sh ./input.csv ./out --dry-run
EOF
}
Tailor the body to the specific script; keep instructions kind and explicit.
Script Assembly Checklist
- •Write header, safety settings, and optional metadata comments.
- •Define requirement arrays (even if empty) and defaults for optional values.
- •Implement
usage()andcheck_requirements()exactly once. - •Parse arguments safely (
getoptsor manual loop) and convert into named variables. - •Call
check_requirementsimmediately after parsing. If it fails, exit withexit 1. - •Implement
main()with clear, modular helpers; rely on functions instead of sprawling inline code. - •End with
main "$@"and ensure the script returns appropriate exit codes.
Phase 4 · Validate, Format, and Hand Off
- •
Self-check
- •Does the script run without arguments and show
usage? - •Do missing env vars and programs produce the friendly errors described earlier?
- •Do all branches respect
set -euo pipefail(guard nullable variables with${VAR:-})?
- •Does the script run without arguments and show
- •
Formatting via
shfmt- •Detect availability:
if command -v shfmt >/dev/null 2>&1; then ... fi - •Run
shfmt -i 2 -bn -ci -sr -w <path-to-script>after writing the file. - •Mention in your response whether formatting ran or was skipped (and why).
- •Detect availability:
- •
Final Response Checklist
- •Provide the complete script in a fenced code block (label it
bash). - •Summarize how requirements are enforced.
- •If manual formatting was necessary (no
shfmt), note it explicitly. - •Suggest any quick validation commands (dry runs, linting) if relevant.
- •Provide the complete script in a fenced code block (label it
Reference Template
Use this skeleton as a starting point and adapt each section based on the user's requirements:
#!/usr/bin/env bash
set -euo pipefail
# Script: <name>
# Purpose: <one-line description>
# Requirements: <short summary of args/env/programs>
REQUIRED_ARGS=("arg1" "arg2")
REQUIRED_ENV_VARS=("ENV_VAR")
REQUIRED_PROGRAMS=("curl" "jq")
usage() {
cat <<'EOF'
Usage: <script-name> <arg1> <arg2>
Required arguments:
arg1 <describe>
arg2 <describe>
Environment variables:
ENV_VAR <describe>
External tools:
curl, jq
EOF
}
check_requirements() {
local -r provided_arg_count=$1
local missing=0
if [ ${#REQUIRED_ARGS[@]} -gt 0 ] && [ "$provided_arg_count" -lt ${#REQUIRED_ARGS[@]} ]; then
printf 'Error: Expected %s arguments (%s) but received %s.\n' \
${#REQUIRED_ARGS[@]} "${REQUIRED_ARGS[*]}" "$provided_arg_count" >&2
missing=1
fi
local env_var
for env_var in "${REQUIRED_ENV_VARS[@]}"; do
if [ -z "${!env_var:-}" ]; then
printf 'Error: Missing required environment variable %s. Please set it before rerunning.\n' "$env_var" >&2
missing=1
fi
done
local program
for program in "${REQUIRED_PROGRAMS[@]}"; do
if ! command -v "$program" >/dev/null 2>&1; then
printf 'Error: Required program %s is not installed or not on PATH. Please install it first.\n' "$program" >&2
missing=1
fi
done
if [ "$missing" -ne 0 ]; then
printf '\n' >&2
usage >&2
return 1
fi
}
parse_args() {
# TODO: replace with real parsing
SOURCE=${1:-}
DEST=${2:-}
}
main() {
parse_args "$@"
check_requirements "$#" || exit 1
# TODO: script logic goes here
printf 'Running with source=%s dest=%s\n' "$SOURCE" "$DEST"
}
main "$@"
Update placeholders, replace TODO sections, and adjust arrays when a requirement does not apply (leave the array empty—do not delete it).
Quality Checklist Before Finishing
- • Script declares all requirement arrays and the
check_requirementsfunction - • Error messages are friendly, specific, and routed to STDERR
- • Script avoids Bash ≥4 features and has been reviewed for 3.2 compatibility
- •
usage()accurately reflects arguments, env vars, and dependencies - • Formatting completed with
shfmt(or explicitly noted why it was skipped) - • Final response contains both summary guidance and the full script for copy/paste