Generates production Bash scripts with a visual timeline UI, state-based interactive prompts, and strict error handling. Use when asked for "a human-facing shell tool", an interactive bash script, or a DevOps tool with framed terminal output. Do NOT use for a non-interactive automation, CI, or pipeline script, that is `bash-cli-script`.
Scanned 9/2/2026
Install to Claude Code
npx -y skills add erclx/canon --skill bash-script --agent claude-codeInstalls into .claude/skills of the current project.
Are you the author of Bash Script?
Add the live security badge to your README — it updates automatically with every re-scan.
[](https://www.skillsdirectory.com/skills/erclx-bash-script)More formats (shields.io, HTML) on the badges page.
---
name: bash-script
description: Generates production Bash scripts with a visual timeline UI, state-based interactive prompts, and strict error handling. Use when asked for "a human-facing shell tool", an interactive bash script, or a DevOps tool with framed terminal output. Do NOT use for a non-interactive automation, CI, or pipeline script, that is `bash-cli-script`.
---
# Bash script
Generate production-ready Bash scripts for DevOps and CLI workflows. Enforce strict formatting with a visual timeline UI and state-based interactivity.
Load `${CLAUDE_SKILL_DIR}/references/patterns.md` for the timeline lifecycle, logging, interactive prompt, help-screen, and full-script code templates. `${CLAUDE_SKILL_DIR}` expands to this skill's own directory, so the path resolves from any project. Copy those definitions verbatim, keeping only the colors and functions the script actually uses.
## Guards
- A request for a script with no human at the terminal stops and routes to `bash-cli-script`. CI jobs, cron entries, agent-run tasks, and any script whose output is consumed by a pipe render no timeline, so generating one costs the frame and returns nothing.
## Script setup
- Start with `#!/usr/bin/env bash`, `set -e`, and `set -o pipefail`.
- Bash 4+ features (namerefs, associative arrays) are allowed.
- Implement a visual help screen via `show_help` if the script accepts arguments.
- Do not rely on unset variables. Use `${VAR:-default}`.
## Visual timeline
- Maintain a vertical timeline (`│`) from `┌` to `└` throughout all output.
- Write all frame output (`┌`, `│`, `├`, `└`, log lines, prompts) to stderr via `>&2`. Write data (JSON, lists, piped values) to stdout. `--help` is the exception and prints to stdout.
- Open the timeline once at the start of `main()` via `open_timeline "Title"`, before any logic, prompts, or checks.
- Close the timeline via `trap close_timeline EXIT`, registered immediately after `open_timeline`.
- On success, disable with `trap - EXIT`, then print `└\n` and the success message manually.
- On cancellation and error, never print `└` manually. The trap owns those exits.
- Use state transitions for interactive prompts: `◆` active, `◇` inactive.
- Do not add diamonds (`◆` or `◇`) to non-interactive log functions.
- On cancellation, show `◇ ... Cancelled`, exit 1, and make no `log_error` call. Both `ask()` and `select_option()` handle escape cancellation identically.
- Guard interactive prompts against non-TTY stdin with `[ -t 0 ]` and render a framed `log_error` when a TTY is required but absent. Never let `read` block silently on piped input.
## Code style
- Decompose by responsibility: each function does one thing, `main()` orchestrates only.
- Name functions verb-first: `validate_input`, `deploy_service`, `install_dependencies`.
- Do not use global variables except exports from `ask()`.
- Do not define unused color variables.
- Comment only a fact the reader cannot recover from the code, and follow the code-comment rule in `.claude/rules/` when the project installs it.
- Use sentence case for section headers and log messages. Proper nouns and product names retain their casing.
- Quote variables inside parameter expansions: `"${file#"$dir"/}"` not `"${file#$dir/}"`.
- Quote variables in test brackets: `[ "$i" -eq "$cur" ]` not `[ $i -eq $cur ]`.
- Guard commands that return non-zero on valid empty results: `grep ... || true`, `diff ... || true`.
## Output hygiene
- Show external tool output by default (git, npm, gh).
- Include context in error messages: `log_error "npm install failed: check package.json"`.
- Do not echo command names before running them. Output speaks for itself.
- Do not log "Starting..." and "Finished..." around every action.
- Do not log intermediate variable assignments.
- Use `log_add` for item writes (files created, entries added, keys written).
- Use `log_info` for status confirmations only ("up to date", "check passed").
- Use `log_warn` for drift, skipped states, or recoverable issues.
- Never use `log_info` for file or entry writes.
## Icon usage
Interactive prompts only:
- `◆` (green): active user input required
- `◇` (grey): completed input, transition via `\r\033[K` to rewrite the `◆` line in place
- `❯` (green): selected option in a menu
- plain text (grey): unselected option in a menu
Non-interactive logs:
- `├` section branch (`log_step`)
- `✓` (green): success (`log_info`)
- `!` (yellow): warning (`log_warn`)
- `✗` (red): error (`log_error`)
- `+` (green): add item (`log_add`)
- `-` (red): remove item (`log_rem`)
## Validation
Before responding, verify:
- File starts with `#!/usr/bin/env bash`, `set -e`, `set -o pipefail` and uses exactly 2 spaces for indentation.
- Timeline opens via `open_timeline "Title"`, which writes `┌` and `│ Title` to stderr.
- Timeline closes via `trap close_timeline EXIT` registered immediately after `open_timeline`. Success paths use `trap - EXIT` then manual `└\n` (to stderr) then the success message. Cancellation and error paths never print `└` manually.
- `open_timeline` and `close_timeline` are defined and write to stderr via `>&2`.
- All frame output (`│`, `├`, `└`, log lines, interactive prompts) writes to stderr via `>&2`. Stdout carries data only. `--help` is the exception.
- Interactive prompts (`ask`, `select_option`) guard with `[ -t 0 ]` and call `log_error` if stdin is not a TTY.
- The timeline (`│`) appears in all log functions, and interactive prompts use `◆` → `◇` transitions.
- `ask()` uses `\r\033[K` to rewrite the `◆` line in place, with no `\033[1A` cursor-up sequences.
- `ask()` drains trailing escape bytes with `read -rsn2 -t 0.001 _ || true` before cancelling.
- All log messages use sentence case (proper nouns and product names exempt).
- Only defined color variables are used in the script.
- Cancellation shows a single `◇ ... Cancelled` line without a subsequent `log_error`.
- Escape key in `ask()` triggers `◇ ... Cancelled` and exits, consistent with `select_option()`.
- Functions follow single responsibility: each does one thing, `main()` delegates to helpers.
- Logging is concise: no "Starting.../Finished..." bloat, no intermediate variable logging.
- `log_add` is used for all file, entry, and key writes.
- `log_info` is used for status confirmations only, not writes.
- Every section header uses `log_step`, including the first one after the title block.
- File ends with exactly one empty line.
Is this your skill, or is something wrong with this listing? Request removal or report an issue. Author removals are honored within 72 hours.
No comments yet. Be the first to comment!