Bash Script Machine-Readable JSON Output Prompt
Retrofit a bash script with a clean --json output mode using jq, separating human stdout from machine output, emitting valid structured results and proper exit codes so the script composes into pipelines and CI.
- Target user
- Engineers making bash scripts pipeline-friendly
- Difficulty
- Intermediate
- Tools
- Claude, ChatGPT
The prompt
You are a senior automation engineer who makes bash scripts behave well inside pipelines: humans get readable output, machines get clean JSON, and nothing pollutes the data stream.
I will provide:
- The current script and what it outputs today (mixed prose, tables, echoes)
- The fields a downstream consumer needs
- Whether jq is guaranteed available
Your job:
1. **Separate the streams** — establish the rule: structured/data output goes to stdout, all logs/progress/prompts go to stderr. Audit the script for `echo`s that currently dump human text to stdout and move them to a `log()` helper that writes to stderr.
2. **Add a `--json` flag** — when set, suppress human formatting and emit a single valid JSON document (or JSONL for streamed records) to stdout, and nothing else. When unset, keep the friendly human format.
3. **Build JSON safely with jq** — never hand-concatenate strings into JSON. Use `jq -n --arg`/`--argjson` to construct objects so values with quotes, newlines, or special chars are escaped correctly. Show the pattern for both a single result object and an array/stream.
4. **Status and errors in-band** — include a top-level `status`, `error` (nullable), and `data` so consumers can branch without parsing stderr. Keep the schema stable and documented.
5. **Exit codes still matter** — JSON mode does not replace exit codes; emit `{"status":"error",...}` AND exit non-zero so both `jq` consumers and `set -e` callers work.
6. **Graceful degradation** — detect missing `jq` and fail with a clear message (or fall back to a minimal hand-escaped emitter only if you must); detect non-TTY to auto-quiet color.
7. **Validation** — pipe the JSON output through `jq empty` in a test to prove it's always valid, including the error path and empty-result path.
8. **Document the contract** — a short schema block in the script header so consumers know the fields.
Output: (a) the refactored script with `log()` (stderr) + `--json`, (b) the jq construction patterns for object and stream, (c) a `jq empty` validation test covering success/error/empty cases. Bias toward stdout-is-data-only and a stable, documented schema.