Claude-skill-registry bash-script-generator
Generate Bash 3.2-compatible scripts with a standardized check_requirements guardrail, friendly validation errors, and optional shfmt formatting. Use when writing or updating bash scripts that need consistent argument validation, dependency checks, and portability.
git clone https://github.com/majiayu000/claude-skill-registry
T=$(mktemp -d) && git clone --depth=1 https://github.com/majiayu000/claude-skill-registry "$T" && mkdir -p ~/.claude/skills && cp -r "$T/skills/data/bash-script-generator" ~/.claude/skills/majiayu000-claude-skill-registry-bash-script-generator && rm -rf "$T"
skills/data/bash-script-generator/SKILL.mdStructured 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
function that validates inputs and dependencies kindlycheck_requirements - 🛡️ Ensure the script sets safe defaults (
), quotes expansions, and keeps logic portable to macOS/Linux Bash 3.2set -euo pipefail - ✨ Format the script with
when available and return a polished result ready for immediate useshfmt
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
-only scripts (no Bash-specific features allowed)sh - 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
). Note install hints when useful.jq - 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
andcheck_requirementsmessaging.usage
Phase 2 · Plan the Script Structure
Lay out the sections before writing code:
-
Header & Safety
#!/usr/bin/env bashset -euo pipefail
only if tighter word splitting is needed.IFS=$'\n\t'
-
Metadata Comments (optional)
- Summarize script purpose and prerequisites in commented lines for discoverability.
-
Usage Helper
- A
function that prints how to run the script, expected args, environment variables, and examples.usage()
- A
-
Requirement Configuration
- Define
,REQUIRED_ARGS
, andREQUIRED_ENV_VARS
as indexed arrays (compatible with Bash 3.2). When nothing is required, keep the arrays empty but present.REQUIRED_PROGRAMS - Optionally define associative-looking notes via comments or simple
statements; do not usecase
(requires Bash ≥4).declare -A
- 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
for short flags. For long options, parse manually with agetopts
loop; avoidwhile
if portability is uncertain.getopt - Populate variables for downstream logic (use
to coexist with${VAR:-}
).set -u
- Prefer
-
Main Logic
- Encapsulate primary workflow in
and finish withmain()
.main "$@"
- Encapsulate primary workflow in
Phase 3 · Compose the Script
Follow this recipe while writing the actual script content.
Required Guardrail: check_requirements
check_requirementscheck_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
right after argument parsing, e.g.check_requirements
.check_requirements "$#" - If the script allows optional trailing arguments, keep
limited to the mandatory ones and validate optional parameters separately afterREQUIRED_ARGS
succeeds.check_requirements "$#" - Keep error language supportive (“Please install…”) rather than punitive.
- Route any diagnostics to STDERR (
) and exit gracefully with>&2
so the caller canreturn 1
or handle it.exit 1 - Only call
from error paths (like failed requirement checks) so successful runs stay quiet unless the user explicitly asks for help.usage
Bash 3.2 Compatibility Guardrails
- Use indexed arrays only; no associative arrays or namerefs (
).local -n - Avoid
with capture groups that rely on Bash ≥3.2. Basic regex is fine, but keep patterns simple.[[ string =~ regex ]] - Do not rely on
,mapfile
,readarray
,coproc
, or process substitution that requiresprintf -v
(often missing on macOS)./dev/fd - Prefer
subshells over backticks and quote every expansion.$( command ) - Use
instead ofprintf
for reliable escape handling.echo -e
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
andusage()
exactly once.check_requirements() - Parse arguments safely (
or manual loop) and convert into named variables.getopts - Call
immediately after parsing. If it fails, exit withcheck_requirements
.exit 1 - Implement
with clear, modular helpers; rely on functions instead of sprawling inline code.main() - End with
and ensure the script returns appropriate exit codes.main "$@"
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
(guard nullable variables withset -euo pipefail
)?${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
after writing the file.shfmt -i 2 -bn -ci -sr -w <path-to-script> - 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
), note it explicitly.shfmt - 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
functioncheck_requirements - Error messages are friendly, specific, and routed to STDERR
- Script avoids Bash ≥4 features and has been reviewed for 3.2 compatibility
-
accurately reflects arguments, env vars, and dependenciesusage() - Formatting completed with
(or explicitly noted why it was skipped)shfmt - Final response contains both summary guidance and the full script for copy/paste