Bash tool escapes ! to \! when adjacent to whitespace
Description
The Bash tool inserts a backslash before ! when it is adjacent to whitespace, even inside single quotes and in a non-interactive shell where history expansion is already disabled.
Reproduction
printf '%s' ' != ' | xxd
# Expected: 20 21 3d 20 ( != )
# Actual: 20 5c 21 3d 20 ( \!= )
Pattern
| Input | Output | Correct? |
|-------|--------|----------|
| ' != ' | \!= | BUG |
| '!=' | != | OK |
| '! ' | \! | BUG |
| 'x!' | x! | OK |
| 'x! ' | x\! | BUG |
| 'a!b' | a!b | OK |
! is escaped when adjacent to whitespace, but preserved when between non-whitespace characters.
Impact
Breaks any command-line tool or DSL that uses != with standard spacing, as the tool receives \!= instead.
Environment
- Claude Code 2.1.72
- bash 5.2.15(1)-release, macOS Darwin 21.6.0
- Shell is non-interactive,
histexpandis off
Analysis
The escaping happens in the Bash tool layer before the command reaches the shell. It appears to be an overzealous history expansion prevention that doesn't account for single-quoted contexts or non-interactive shells where ! is already literal.
4 Comments
This is a shell-quoting issue in Claude Code's command escaping layer. It applies history expansion escaping even in non-interactive mode where
!has no special meaning.printfbypasses the escaping issue because Claude Code's escaper may only target certain output functions.This appears to be fixed as of Claude Code 2.1.87. Tested all six cases from the original report with both echo and printf — no spurious \ escaping observed:
| Command | Result | Correct? |
|-------|--------|----------|
| printf '%s' ' != ' | xxd → 20 21 3d 20 | ✓
| printf '%s' '! ' | xxd → 21 20 | ✓
| printf '%s' 'x! ' | xxd → 78 21 20 | ✓
| echo ' != ' | xxd → 20 21 3d 20 0a | ✓
| echo '! ' | xxd → 21 20 0a | ✓
| echo 'x! ' | xxd → 78 21 20 0a | ✓
No 5c byte anywhere. The !-adjacent-to-whitespace escaping bug is resolved for both echo and printf.
I recently spent a few hours tracking down a wild edge-case related to this exact shell escaping behavior in Claude Code, and I wrote a full post-mortem about it.
For context: before the 2.1.92 update, the shell-quote library used in shellQuoting.ts was silently escaping exclamation marks (turning ! into \!) before wrapping commands in eval. I used Claude Code to generate a Tauri signing key, and it silently injected that backslash into my password without me knowing. It worked flawlessly for 20 releases.
When Claude Code updated to 2.1.92 and the escaping behavior was fixed, my release pipeline suddenly broke with a Wrong password error. The "correct" password no longer matched because the original key was generated with the buggy shell-quote behavior! A perfect real-world example of Hyrum's Law.
I used the JSONL command logs generated by Claude Code to trace this down. If anyone else is running into weird side effects after the recent bash tool updates, or dealing with corrupted interactive CLI inputs, this might give you some context:
https://max.nardit.com/articles/the-invisible-backslash
Thanks for fixing the bug in 2.1.92, even if it temporarily broke my workflow! 😄
This issue has been automatically locked since it was closed and has not had any activity for 7 days. If you're experiencing a similar issue, please file a new issue and reference this one if it's relevant.