[BUG] Bash tool escapes `!` in file paths
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 automatically escapes ! to \! before passing commands to the shell. This happens at the tool level, not in the shell itself, so no quoting strategy (single quotes, set +H, manual escaping) can prevent it. Any file or directory with ! in its name is inaccessible via the Bash tool.
What Should Happen?
The Bash tool should pass ! through to the shell unmodified. Shell-level quoting (single quotes) is sufficient to handle zsh history expansion - the tool should not add its own escaping on top.
Error Messages/Logs
$ ls '/tmp/test-!-dir/'
ls: /tmp/test-\!-dir/: No such file or directory
Note the `\!` - the tool inserted a literal backslash before `!`. All quoting strategies produce the same result:
ls '/tmp/test-!-dir/' # → \! in error
ls "/tmp/test-!-dir/" # → \! in error
ls /tmp/test-\!-dir/ # → \\! in error
set +H && ls '/tmp/test-!-dir/' # → \! in error
Steps to Reproduce
- In a normal terminal, create a test directory:
```bash
mkdir '/tmp/test-!-dir'
touch '/tmp/test-!-dir/file.txt'
2. In Claude Code, ask Claude to run: `ls '/tmp/test-!-dir/'`
3. The command fails with `No such file or directory`, showing `\!` in the path
Workaround - use Python to avoid `!` in command arguments:
```bash
python3 << 'EOF'
import os
print(os.listdir('/tmp/test-!-dir'))
EOF
Claude Model
Opus
Is this a regression?
I don't know
Last Working Version
_No response_
Claude Code Version
2.1.86
Platform
Anthropic API
Operating System
macOS
Terminal/Shell
iTerm2
Additional Information
Discovered while trying to mv a directory named !image_generation_workflow. Every direct shell command (mv, git mv, ls) failed. The only workaround was delegating to Python via heredoc, which bypasses the tool's escaping layer.
This issue has 3 comments on GitHub. Read the full discussion on GitHub ↗