Skip to content

Feature request: opt-in to preserve ${var} braces (SC2250 interop) #68

Description

@Pierre-Gronau-ndaal

Feature request: opt-in to preserve ${var} braces (SC2250 interop)

Summary

Add an option (e.g. --keep-braces, or a --replace/--transform modifier) that makes Shellharden apply its quoting corrections without stripping the curly braces from simple variable expansions — i.e. keep "${var}" as "${var}" instead of rewriting it to "$var".

Motivation — why this adds value

Shellharden's stated purpose is to "make your script ShellCheck compliant in terms of quoting." That is exactly why it is valuable, and exactly why this gap stings: there is one ShellCheck check that Shellharden actively works against.

ShellCheck ships SC2250require-variable-braces:

Prefer putting braces around variable references even when not strictly required.

SC2250 is opt-in, but it is enabled deliberately by many projects — either explicitly or via enable=all in .shellcheckrc. For those projects, braces on every expansion are a mandatory house style, enforced as a CI gate.

Today the two tools are in direct opposition:

  • shellcheck (with SC2250 on) adds braces: "$var" -> "${var}".
  • shellharden --replace removes them: "${var}" -> "$var".

The result is a loop that cannot converge. Running one tool re-introduces the exact findings the other just fixed. A project that wants Shellharden's quoting hardening and an SC2250-clean tree currently cannot have both from an automated pipeline — it has to disable Shellharden's autofix entirely, losing the quoting benefit, purely to avoid the brace churn.

An opt-in "keep braces" mode fixes this with no downside:

  • It broadens adoption — every SC2250/enable=all codebase becomes a candidate for --replace in CI, instead of report-only.
  • It increases Shellharden's ShellCheck conformance, the tool's own headline goal: today --replace output is not SC2250-clean; with this flag it would be.
  • It is purely additive — default behaviour is unchanged, so no existing user is affected.

Current behaviour (reproduction)

Tested with Shellharden 4.3.2 (latest release):

$ shellharden --transform sh_test.sh
#!/usr/bin/env bash
foo=bar
echo "$foo"          # <-- braces stripped
echo "$foo"
printf '%s\n' "${foo}/baz"   # kept (syntactically required here)

Shellharden already correctly keeps braces where they are load-bearing (${foo}/baz), so the requested mode is a natural extension: keep them in the simple case too, when the user asks for it.

Proposed behaviour

shellharden --replace --keep-braces script.sh
shellharden --transform --keep-braces script.sh

All normal quoting corrections still apply; only ${...} braces are left intact — producing output that satisfies both Shellharden's quoting rules and SC2250. Flag spelling is maintainer's choice; the request is for the capability.

Alternatives considered

  • Run Shellharden report-only (current workaround) — throws away the automation.
  • Disable SC2250 — not viable where a style guide/enable=all mandates braces.
  • Post-process to re-add braces — fragile, duplicates ShellCheck's logic.

Impact

  • Backward compatible: default output byte-for-byte unchanged.
  • Unlocks --replace in CI for every SC2250 / enable=all project.
  • Advances Shellharden's own goal of ShellCheck conformance.

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions