bash-script-generator
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 bashset -euo pipefailIFS=$'\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