#!/bin/sh set -eu INPUT="${1:?input file required}" OUTPUT="${2:?output file required}" mkdir -p "$(dirname "$OUTPUT")" TMP="$(mktemp)" BASE_CREATED=0 if [ -f "$OUTPUT" ]; then BASE="$OUTPUT" else BASE="$(mktemp)" BASE_CREATED=1 : > "$BASE" fi cleanup() { rm -f "$TMP" if [ "$BASE_CREATED" = "1" ]; then rm -f "$BASE" fi } trap cleanup EXIT INT TERM awk ' function trim(s) { sub(/^[[:space:]]+/, "", s) sub(/[[:space:]]+$/, "", s) return s } function parse_key(line, eq, key) { eq = index(line, "=") if (eq == 0) { return "" } key = trim(substr(line, 1, eq - 1)) if (key !~ /^[A-Za-z_][A-Za-z0-9_]*$/) { return "" } return key } function merged_line(key, line) { if (key ~ /^MKS_/ && key in ENVIRON) { return key "=" ENVIRON[key] } return line } # First file: INPUT phase == 1 { line = $0 key = parse_key(line) if (key != "") { incoming[key] = merged_line(key, line) if (!(key in input_seen)) { input_order[++input_count] = key input_seen[key] = 1 } } next } # Second file: existing OUTPUT / BASE phase == 2 { line = $0 key = parse_key(line) if (key != "" && key in incoming) { print incoming[key] written[key] = 1 next } print line if (key != "") { written[key] = 1 } next } END { for (i = 1; i <= input_count; i++) { key = input_order[i] if (!(key in written)) { print incoming[key] written[key] = 1 } } } ' phase=1 "$INPUT" phase=2 "$BASE" > "$TMP" mv "$TMP" "$OUTPUT"