Summary
In double-quoted strings, \$ should produce a literal $ character. Bashkit instead treats the $ as a variable expansion marker after the backslash is stripped, causing unintended variable expansion.
Reproduction
# FAIL — \$ should be literal
echo "\$HOME"
# expected: $HOME
# actual: /root (or whatever HOME is set to)
# FAIL — with set -u, causes unbound error
set -u
echo "\$nonexistent"
# expected: $nonexistent
# actual: bash: nonexistent: unbound variable
# FAIL — breaks embedded perl/awk
perl -e "\$x = 42; print \$x"
# expected: perl sees "$x = 42; print $x"
# actual: bash expands $x before perl sees it
# PASS — single quotes (no expansion, verify no regression)
echo '\$HOME'
# expected: \$HOME
# actual: \$HOME ✓
Spec tests to add
### backslash_dollar_in_double_quotes
# \$ in double quotes should produce literal $
echo "\$HOME"
### expect
$HOME
### end
### backslash_dollar_with_text
# \$ followed by identifier should not expand
echo "\$foo bar"
### expect
$foo bar
### end
### backslash_dollar_set_u
# \$ should not trigger unbound variable under set -u
set -u
echo "\$undefined_var"
### expect
$undefined_var
### end
### backslash_dollar_in_assignment
# Assignment with \$ should preserve literal
x="\$PATH"
echo "$x"
### expect
$PATH
### end
Where to fix
The lexer at crates/bashkit/src/parser/lexer.rs (around line 1111) correctly converts \$ to a $ character. But then parse_word() at crates/bashkit/src/parser/mod.rs:2539 re-interprets the resulting $ as a variable expansion marker.
The fix needs to distinguish between a $ that came from \$ escaping (should be literal) and a genuine $ expansion marker. Options:
- Have the lexer emit an escape-sentinel that
parse_word() recognizes as literal
- Have the lexer produce a distinct token/character for escaped-dollar
- Track escape origin in the character stream so
parse_word() can skip expansion
Real-world impact
Critical — \$ in double quotes is extremely common in bash scripts that embed other languages (perl, awk, python). The wedow/harness str_replace tool uses perl -i -0pe "\$old = quotemeta(q{...})" which fails completely in bashkit. Any script using echo "\$var" for literal output also breaks.
Summary
In double-quoted strings,
\$should produce a literal$character. Bashkit instead treats the$as a variable expansion marker after the backslash is stripped, causing unintended variable expansion.Reproduction
Spec tests to add
Where to fix
The lexer at
crates/bashkit/src/parser/lexer.rs(around line 1111) correctly converts\$to a$character. But thenparse_word()atcrates/bashkit/src/parser/mod.rs:2539re-interprets the resulting$as a variable expansion marker.The fix needs to distinguish between a
$that came from\$escaping (should be literal) and a genuine$expansion marker. Options:parse_word()recognizes as literalparse_word()can skip expansionReal-world impact
Critical —
\$in double quotes is extremely common in bash scripts that embed other languages (perl, awk, python). The wedow/harnessstr_replacetool usesperl -i -0pe "\$old = quotemeta(q{...})"which fails completely in bashkit. Any script usingecho "\$var"for literal output also breaks.