Skip to content

executor: a lone $ is a literal, not the shell pid (#672) - #748

Merged
berrym merged 1 commit into
masterfrom
fix/672-dangling-dollar
Aug 16, 2026
Merged

executor: a lone $ is a literal, not the shell pid (#672)#748
berrym merged 1 commit into
masterfrom
fix/672-dangling-dollar

Conversation

@berrym

@berrym berrym commented Aug 16, 2026

Copy link
Copy Markdown
Owner

Closes #672.

The defect

$$ is the process ID. A single $ introduces nothing — there is no parameter named "" — so the only coherent reading is the character itself. An explicit special case returned the PID:

$ lush -c 'echo $'
71681                    # bash, zsh, dash: $
$ lush -c 'v=$; echo "[$v]"'
[71681]                  # stores a pid

Every other position was already correct — a$, "$", '$', 5$, $%, cost: 5$ all produced the literal. That is why it only showed when the $ stood alone as an unquoted word, and why it survived so long.

Curation

  • Baselines: bash, zsh and dash all print the literal.
  • lush's own model: same answer, derived independently.
  • Can lush do better than all three? No. A lone $ has one sensible meaning and this is it. Recorded rather than left implicit; mode-invariant, gates nothing.

On the audit blind spot

The issue noted the CST audit could not flag this, because the legacy and CST paths were equally wrong — there was no divergence to catch. Both were verified to agree after the fix: default CST route, LUSH_WORD_CST=0, and under LUSH_WORD_CST_AUDIT=1 (no abort).

Verification

  • tests/integration/test_dangling_dollar.c — 24 checks: the lone $ in eight positions (whole word, before another word, assigned, doubled, through a pipe, inside a substitution, as a printf argument, in a for list); $$ still a pid, asserted by shape since it has no fixed value; $? and $# untouched; the six positions that were already correct; and six where a $ sits adjacent to a real expansion ($v$, $(printf x)$, $((1+1))$, ${HOME:+x}$) that must not be disturbed.
  • 9 of 24 fail against the parent build, with a control proving the binaries differ.
  • Full suite 196/196. ASan 65/65; the new test 1/1 under ASan.

`$$` is the process ID. A single `$` introduces nothing -- there is no
parameter named "" -- so the only coherent reading is the character itself.
An explicit special case returned the PID instead:

    echo $        ->  71681        bash, zsh, dash: $
    v=$           ->  stores the pid

Every OTHER position was already correct -- `a$`, `"$"`, `'$'`, `5$`, `$%`
and `cost: 5$` all produced the literal -- which is why this only showed when
the `$` stood alone as an unquoted word, and why it survived so long.

bash, zsh and dash all print the literal and lush's own model gives the same
answer independently, so the fix is mode-invariant and gates nothing. Asked
explicitly whether lush can do better than the three here: no. A lone `$` has
one sensible meaning and this is it.

Both expansion paths were verified to agree afterwards (default CST route,
LUSH_WORD_CST=0, and under LUSH_WORD_CST_AUDIT), since the issue noted the
audit could not see this one: legacy and CST were equally wrong, so nothing
diverged for it to catch.

tests/integration/test_dangling_dollar.c: 24 checks -- the lone `$` in eight
positions (word, before another word, assigned, doubled, through a pipe,
inside a substitution, as a printf argument, in a for list), `$$` still a pid
by shape, `$?`/`$#` untouched, the six positions that were already correct,
and six where a `$` sits next to a REAL expansion that must not be disturbed.
9 fail against the parent build.
@berrym
berrym merged commit d78f22c into master Aug 16, 2026
6 checks passed
@berrym
berrym deleted the fix/672-dangling-dollar branch August 16, 2026 11:42
@codecov

codecov Bot commented Aug 16, 2026

Copy link
Copy Markdown

Codecov Report

✅ All modified and coverable lines are covered by tests.

📢 Thoughts on this report? Let us know!

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Lone dangling $ expands to the shell PID (bash/zsh print a literal $)

1 participant