Bash tool escapes ! to \! when adjacent to whitespace

Status Fixed / completed
Reported on v2.1.72
Maintainer reply None cached
Activity 4 comments · opened Mar 10, 2026 · closed Mar 31, 2026

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, histexpand is 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.

View original on GitHub ↗

4 Comments

yurukusa · 6 months ago

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.

echo 'a != b'
printf '%s\n' 'a != b'

printf bypasses the escaping issue because Claude Code's escaper may only target certain output functions.

echo "a $(printf '\x21')= b"
When generating Bash commands with ! characters adjacent to spaces, use printf instead of echo to avoid the \! escaping bug.
treerz · 6 months ago

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.

mnardit · 6 months ago

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! 😄

github-actions[bot] · 6 months ago

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.