Bash Heredoc and envsubst Config Templating Prompt
Generate config files, manifests, and scripts from templates in Bash using heredocs and envsubst — with controlled variable expansion, quoting safety, and no accidental shell interpretation of the payload.
- Target user
- Engineers rendering config files and manifests from shell without a templating engine
- Difficulty
- Beginner
- Tools
- Claude, ChatGPT
The prompt
You are a senior platform engineer who has cleaned up generated configs corrupted by stray `$` signs, backticks, and unquoted heredocs.
I will provide:
- A target config/manifest format (nginx, systemd unit, YAML, JSON, a .env, etc.)
- Which values are dynamic vs literal
- Where the rendered output must be written and with what permissions
Your job:
1. **Pick quoted vs unquoted heredocs deliberately** — explain that `<<EOF` expands `$var`, command substitution, and backticks, while `<<'EOF'` (quoted delimiter) emits the body verbatim. Choose per template and say why. Use `<<-EOF` only when tab-indentation cleanup is needed.
2. **Render only the intended variables** — when the payload itself contains `$` (e.g. nginx `$host`, shell snippets), prefer a quoted heredoc plus `envsubst '${VAR1} ${VAR2}'` with an explicit allowlist so only your placeholders are substituted and the rest stay literal.
3. **Write safely** — render to a `mktemp` file, validate it (e.g. `nginx -t`, `systemd-analyze verify`, `jq .`, `yq`), then atomically `mv` into place with `chmod`/`chown` set before the move. Trap-clean the temp file.
4. **Escape correctly** — show how to embed literal `$`, backslashes, and the delimiter word itself; warn against the classic bug of an indented closing delimiter that never matches.
5. **Guard the inputs** — quote all variable references, reject empty required values up front, and note injection risk when template values come from untrusted sources.
6. **Know when to graduate** — flag the point where logic in the template means it belongs in a real engine (Jinja2 via a small Python helper, gomplate) instead of shell.
Output as: (a) the rendering function with validate-then-atomic-write, (b) a worked example for the requested format, (c) a quick-reference table of `<<EOF` vs `<<'EOF'` vs `<<-EOF` vs `envsubst`.
Bias toward: literal-by-default templates, explicit variable allowlists, and validating output before it ever lands at the target path.