[BUG] Incorrect escaping inside backticks: `!` is escaped as `\!`
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?
I ask Claude Code:
Run this command: /bin/echo '`!`'
but it returns:
⏺ Bash(/bin/echo '`!`')
⎿ `\!`
What Should Happen?
Claude should return:
⏺ Bash(/bin/echo '`!`')
⎿ `!`
Steps to Reproduce
Ask Claude Code:
Run this command: /bin/echo '`!`'
Another example:
> Make POST request to `https://echo.zuplo.io/` with this JSON data: {"text":"`!=`"}
⏺ I'll make a POST request to that URL with the JSON data.
⏺ Bash(curl -X POST "https://echo.zuplo.io/" -H "Content-Type: application/json" -d '{"text":"`!=`"}')
⎿ {
"url": "https://echo.zuplo.io/",
"method": "POST",
"body": "{\"text\":\"`\\!=`\"}",
}
vs:
% curl -X POST "https://echo.zuplo.io/" -H "Content-Type: application/json" -d '{"text":"`!=`"}'
{
"url": "https://echo.zuplo.io/",
"method": "POST",
"body": {
"text": "`!=`"
},
}
Claude Model
Sonnet (default)
Is this a regression?
I don't know
Last Working Version
No response
Claude Code Version
2.0.25
Platform
Anthropic API
Operating System
macOS
Terminal/Shell
Terminal.app (macOS)
Additional Information
No response
Found 2 possible duplicate issues:
- https://github.com/anthropics/claude-code/issues/2941
- https://github.com/anthropics/claude-code/issues/7387
This issue will be automatically closed as a duplicate in 3 days.
- If your issue is a duplicate, please close it and 👍 the existing issue instead
- To prevent auto-closure, add a comment or 👎 this comment
🤖 Generated with Claude Code
Is this a major problem? ! is a special character in the shell.
As a workaround you can use this:
! echo !
⎿ !
Is this a major problem?
!is a special character in the shell.As a workaround you can use this:
! echo ! ⎿ !
The real problem is Claude Code can't use the Bash tool to write files that have ``!\ in them. For example, generating markdown that references code with !=.
There are many contexts in the shell where backticks are valid. For example, wrapped in single quotes or a heredoc.
Ah good call. I hadn't considered the backticks since I was focusing on the bang. This does seem like an issue. I did a bit of testing in Claude.
> Print these characters using the bash tool: `!`
⏺ I'll print those characters using the Bash tool:
⏺ Bash(echo '`!`')
⎿ `\!`
⏺ The Bash tool printed: \!
The exclamation mark gets escaped with a backslash in the output, which is expected behavior in bash when using single quotes with history expansion characters.
> why is that?
⏺ The backslash appears because of how bash handles history expansion and special characters:
1. History Expansion: In bash, ! is a special character used for history expansion (like !! for the last command, !$ for the last argument, etc.)
2. When You Run Locally: When you ran echo '!' in your terminal, you got ! without the backslash because your shell directly processed it. Inside single quotes, ! is treated literally in most contexts.
3. When Claude Code Runs It: The Bash tool executes commands through a shell pipeline that may have different settings or processing layers. The backslash before ! is being added as an escape sequence
somewhere in that execution chain - likely to prevent the shell from attempting history expansion.
4. The Backticks: The backticks themselves are preserved because they're inside single quotes, which prevents command substitution.
If you want to see the exact characters without any escaping, you could use:
- printf '%s\n' '!' - printf is more predictable
- cat << 'EOF' with a heredoc
- Or just echo with double quotes: echo "\!"` (escaping the backticks)
The behavior difference you're seeing between your local runs and the tool runs likely comes from different bash settings (like set +H to disable history expansion) or how the command execution environment is
configured.
> OK, print `!` with each of those and we'll see what works
⏺ I'll test each method to see which one prints `!` correctly:
⏺ Bash(printf '%s\n' '`!`')
⎿ `\!`
⏺ Bash(cat << 'EOF'
`!`…)
⎿ `!`
⏺ Bash(echo "\`!\`")
⎿ `!`
⏺ Great! Here are the results:
1. printf '%s\n' '!' → `\!` ❌ (still escaped)
2. cat << 'EOF' heredoc → `!` ✅ (perfect!)
3. echo "\!"` → `!` ✅ (works!)
Winners: Both the heredoc method and the double-quoted echo with escaped backticks work perfectly. The heredoc is probably the cleanest for multi-line content, while the double-quoted echo is simpler for
single-line output.
Interestingly, even printf with single quotes still shows the escaped !, which suggests the escaping is happening at a deeper level in how the Bash tool processes output, not just in the echo command itself.
I suppose as a workaround until this is fixed you could put in your CLAUDE.md either always use the Write tool when writing files and/or always use HEREDOCs when using the Bash tool to write files.
@brandon-fryslie --
Is this a major problem?
!is a special character in the shell.As a workaround you can use this:
! echo ! ⎿ !
It's only a special character in INTERACTIVE shells with history expansion enabled. Noninteractive shells do not treat ! as special, and even interactive shells don't treat it as special inside single quotes. Normal single quotes ('...' as opposed to the ANSI C-like quoting style $'...') don't require anything to be escaped -- only another single quote can be treated as non-literal in that context.
(I hit this very regularly when jq is being used to filter JSON content -- the model can very easily want to run jq 'select(.foo != "bar")', and having that changed to \!= breaks the syntax).