[BUG] Bash tool escapes ! inside single-quoted strings, breaking jq != and other commands

Resolved 💬 2 comments Opened Feb 24, 2026 by carrotRakko Closed Feb 24, 2026

Preflight Checklist

  • [x] I have searched existing issues and this hasn't been reported yet
  • [x] This is a single bug report (please file separate reports for different bugs)
  • [x] I am using the latest version of Claude Code

What's Wrong?

The Bash tool escapes ! to \! even inside single-quoted strings, where bash treats all characters literally. This breaks any command containing ! in single-quoted arguments, most commonly jq's != operator.

Example: Claude generates echo 'hello != world' — the Bash tool transforms it to echo 'hello \!= world' — output is hello \!= world instead of hello != world.

This is particularly disruptive with gh + --jq expressions that use != for filtering, which is a very common pattern when working with GitHub APIs.

What Should Happen?

The Bash tool should pass single-quoted strings through without modification. Inside single quotes, ! has no special meaning in bash and must not be escaped.

Error Messages/Logs

# Bash tool escapes ! inside single quotes:
$ echo 'hello != world'
hello \!= world

# jq expressions with != fail:
$ gh api ... --jq '.[] | select(.name != "bob")'
failed to parse jq expression: unexpected token "\\"

# Verification that bash itself is NOT the cause — writing to a script file
# bypasses the Bash tool's escaping:
$ cat <<'SCRIPT' > /tmp/test.sh
echo 'hello != world'
SCRIPT
$ bash /tmp/test.sh
hello != world

Steps to Reproduce

  1. Start a Claude Code session
  2. Ask Claude to run a command containing != in single quotes, e.g.: echo 'hello != world'
  3. Observe the output: hello \!= world (escaped)
  4. For comparison, write the same command to a script file and execute it via bash /tmp/script.sh — output is correct: hello != world

This confirms the escaping happens in the Bash tool layer, not in bash itself.

Claude Model

Opus

Is this a regression?

I don't know

Claude Code Version

2.1.52 (Claude Code)

Platform

Anthropic API

Operating System

Ubuntu/Debian Linux

Terminal/Shell

Non-interactive/CI environment

Additional Information

Workarounds:

  1. Use | not instead of != in jq (e.g., select(.name == "bob" | not))
  2. Write the command to a temporary script file and execute via bash /tmp/script.sh

Both are viable but add friction and waste context when Claude retries after the initial failure.

✍️ Author: Claude Code with @carrotRakko (AI-written, human-approved)

View original on GitHub ↗

This issue has 2 comments on GitHub. Read the full discussion on GitHub ↗