Write a robust shell script
Writes a portable shell script with strict mode, argument parsing, a dry-run flag, clear errors and idempotent steps. Use when automating a chore you will run more than once.
Shell scripts written in a hurry fail in predictable ways: an unset variable expands to an empty string and rm -rf hits the wrong directory, a failed command in a pipeline is ignored, a filename with a space splits in two, GNU-only flags break on macOS, and a second run duplicates what the first run did. The person needs a script they can run twice, read in a year, and trust in a dry run first.
Write a script for this goal, to run on :
- If the goal leaves out something that decides what gets deleted, overwritten or sent (which paths, which hosts, whether it needs root), ask up to 3 questions and stop. Otherwise state your assumptions and continue.
- Choose the strict-mode preamble for the shell:
- bash:
set -Eeuo pipefail, atrapthat reports the failing line on ERR, and a cleanup trap on EXIT. - zsh:
emulate -L zshandsetopt ERR_EXIT NO_UNSET PIPE_FAIL. - posix-sh:
set -eu. Do not rely onpipefail, arrays,[[ ]],localor$'...'; check pipeline stages explicitly where failure matters. - powershell: a
param()block with[CmdletBinding(SupportsShouldProcess)],Set-StrictMode -Version Latestand$ErrorActionPreference = 'Stop'; check$LASTEXITCODEafter native commands.
- Parse arguments:
-h/--help(usage to stdout, exit 0), long options, required values validated up front, unknown options rejected with usage on stderr and exit 2. In bash and zsh use awhile/caseloop so long options work;getoptshandles only short ones. - Add a dry-run mode (
--dry-run, or-WhatIfin PowerShell) that prints every state-changing command, safely quoted, instead of running it. Route all side effects through one helper so dry run cannot miss one. - Make each step idempotent: test before acting, use
mkdir -pandln -sfn, check before appending to a file, and write files to a temp file on the same filesystem and then move it into place. - Fail clearly: check required tools with
command -vat start-up, print errors to stderr with the script name and a fix, and use distinct non-zero exit codes for distinct failures. - Check the script against ShellCheck (or PSScriptAnalyzer) rules in your head, and fix anything they would flag.
- Quote every expansion. Use
--before user-supplied paths. Never parsels; usefind ... -print0withwhile IFS= read -r -d ''(bash/zsh) or a glob loop. - Guard destructive commands against empty variables with
${VAR:?}, and neverrm -rfa path built from unchecked input. - Portability for macOS and Linux: macOS ships bash 3.2 (no associative arrays,
mapfileor${var,,}) and BSD tools (sed -i '', nodate -d, nogrep -P, differentstatflags). Iftarget_osisanyormacos, avoid these or branch onunameexplicitly. - No secrets in the script, arguments or logs. Read them from the environment or a file with restricted permissions.
- Never fetch remote code and execute it.
- If the job is better done by an existing tool (rsync, a package manager, a cron entry), say so in one line, then write the script anyway.
Assumptions
Bullets, or "None".
Script
One complete code block with a header comment: purpose, usage line, exit codes.
Usage
Two or three example invocations, including a dry run.
What it changes
Every file, directory, service or remote system it creates, modifies or deletes.
How to test it
Steps to try it safely: dry run first, then a throwaway directory or container.
Limitations
What it does not handle, one line each.
1 required value still a placeholder; the assistant will ask for it.
details
- kind
- Prompt: a task you run by name to get one finished thing back
- domain
- Software engineering
- category
- Implementation
- level
- Intermediate
- made for
- Software engineer, DevOps / platform engineer, Site reliability engineer
- risk
- read-only
- version
- v1.0.0 · incubating
- reviewed
- 2026-10-02
- works in
- Claude Code, Codex, Cursor, GitHub Copilot, Gemini CLI, Antigravity, OpenCode, Windsurf, Zed, Continue, AGENTS.md, ChatGPT, claude.ai
use in
npx @hermes-hq/hodios install write-shell-script --target claude-codenpx skills add hermes-hq/hodios-dist --skill write-shell-script -a claude-codeclaude plugin marketplace add hermes-hq/hodios-distclaude plugin install hodios-software-engineering@hodiosThe plugin brings every entry in this domain at once.
more in implementation
All of ImplementationPut a change behind a feature flag
Wraps new behaviour behind a feature flag with a safe default, a kill switch, tests for both paths and a cleanup ticket. Use when shipping a risky change incrementally.
add-feature-flagAdd low-power sleep modes
Adds sleep modes to battery firmware, gating clocks and peripherals, choosing wake sources and state retention, and backs the change with a current measurement plan and battery-life budget.
add-low-power-sleep-modesAdd rate limiting to an API
Adds rate limiting to API endpoints with a fitting algorithm, keys, per-tier limits, standard headers, 429 responses and tests. Use when protecting endpoints from abuse or overload.
add-rate-limitingAdd retries and timeouts to external calls
Adds timeouts, retries with exponential backoff and jitter, idempotency and a circuit breaker to calls to an external service, with tests that simulate failures.
add-retries-and-timeoutsAngular engineer
Acts as a senior Angular engineer who builds with standalone components and services, uses signals or RxJS where each fits, enforces strict typing and keeps change detection efficient.
angular-engineerBackend engineer
Acts as a backend engineer focused on correct data handling, clear API contracts, explicit failure modes and services that are easy to operate. Use as a builder or reviewer persona for server code.
backend-engineer