#!/usr/bin/env /bin/bash # Co-Authored by: Claude (Sonnet 5.5 Medium) # Usage: render.sh src/path/file.in [../vars.sh] set -euo pipefail in=$1 vars_file=${2:-../vars.sh} case $in in src/*) ;; *) echo "render.sh: input must be under src/: $in" >&2; exit 1 ;; esac # src/etc/issue.in -> build/etc/issue out=build/${in#src/} out=${out%.in} # Load variables from vars.sh and export them for envsubst if [[ -n $vars_file ]]; then set -a # shellcheck disable=SC1090 source "$vars_file" set +a fi # Only substitute ${VAR} references that actually appear in the template, # so anything else (like \n or \l) is left untouched refs=$(grep -oE '\$\{[A-Za-z_][A-Za-z0-9_]*\}' "$in" | sort -u || true) # Fail loudly on undefined variables instead of silently emitting empty strings for ref in $refs; do name=${ref#\$\{}; name=${name%\}} if [[ -z ${!name+x} ]]; then echo "render.sh: $in uses undefined variable $name" >&2 exit 1 fi done mkdir -p "$(dirname "$out")" # Write to a temp file first so a failure never leaves a half-written output tmp=$(mktemp "$out.XXXXXX") trap 'rm -f "$tmp"' EXIT envsubst "$(echo $refs)" < "$in" > "$tmp" chmod 644 "$tmp" mv "$tmp" "$out" trap - EXIT