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 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-limitingBackend 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-engineerBuild a REST endpoint end to end
Implements one HTTP endpoint with route, input validation, handler, error mapping and tests in the project's own framework and conventions. Use when adding an API route.
build-rest-endpointBuild a reusable UI component
Builds a typed, accessible UI component from a description or screenshot, with loading, empty and error states and a usage example. Use when adding a component to a frontend.
build-ui-componentBuild a webhook handler
Implements a webhook receiver with signature checks, replay protection, idempotent processing, fast acknowledgement, async work, retries and tests. Use when integrating Stripe, GitHub or similar.
build-webhook-handler