[BUG] Shell script occasionally fails due to crazy escaping
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 have not found a way to reliably reproduce this, but from time to time, Claude Code submits wildly incorrect code to the shell even though the commands are printed with completely the right syntax.
Here is a captured example:
⏺ Bash(for f in $(find . -type f -exec tail -c 1 {} \; -print | grep -v '^$');
do awk 1 "$f" > tmp && mv tmp "$f"; done)
⎿ Error: /opt/homebrew/bin/bash: eval: line 1: syntax error near unexpected
token `('
/opt/homebrew/bin/bash: eval: line 1: `for f in \$ ( find . -type f -exec
tail -c 1 \{\} \; -print < /dev/null | grep -v \^\$ ) ; do awk 1 '' > tmp
&& mv tmp '' ; done'
(I had separately tried to tell Claude to not use find in command substitutions but that's tangential here.)
You'll notice that not only has Claude inserted a spurious </dev/null (which I think is already reported multiple times, though I could quickly find only https://github.com/anthropics/claude-code/issues/4315) but also, the dollar sign in the command substitution has been escaped and weirdly followed by a space.
What Should Happen?
Command lines should not be weirdly escaped when sent to the shell. It would probably be better if Claude Code showed exactly what it's going to try to run so that users who understand this language can intervene and correct (including then any spurious additions of </dev/null etc).
Error Messages/Logs
Error: /opt/homebrew/bin/bash: eval: line 1: syntax error near unexpected token `('
Steps to Reproduce
Like I wrote above, I have not been able to reliably reproduce this. It seems to happen in spurts and then go away again. Perhaps there is something in Claude's internal state which triggers this behavior?
Performing a task where you need Claude Code to do things in the shell seems to exhibit this sooner or later.
Claude Model
Sonnet (default)
Is this a regression?
I don't know
Last Working Version
No response
Claude Code Version
1.0.110 (Claude Code)
Platform
AWS Bedrock
Operating System
macOS
Terminal/Shell
Terminal.app (macOS)
Additional Information
This is probably just another aspect of a more fundamental problem around how Claude Code runs commands. I have found related bugs such as
- https://github.com/anthropics/claude-code/issues/3839 which is however specifically about problems with single-quoted strings containing pipe symbols
- https://github.com/anthropics/claude-code/issues/2941 which is however specifically about exclamation marks (and not only in shell, but in any language). I have observed weird backslashing of exclamation marks in shell snippets, too.
- https://github.com/anthropics/claude-code/issues/841 which seems overtly broad but thematically similar, in that it complains about the amount of unnecessary backslashes
- The insertion of
</dev/nullredirections is something I have seen in multiple bug reports, but see e.g. https://github.com/anthropics/claude-code/issues/4315
Found 3 possible duplicate issues:
- https://github.com/anthropics/claude-code/issues/3839
- https://github.com/anthropics/claude-code/issues/1132
- https://github.com/anthropics/claude-code/issues/4315
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
I frequently encounter bash tool errors like this across my two main environments (macOS & RHEL). When I asked Claude to search my conversation history for examples to add to this issue, it ironically hit this exact error:
⏺ Bash(file="$HOME/.claude/projects/-Users-x-phd/<redacted>.jsonl"; cutoff_date="2025-10-17T00:00:00Z"; timestamp=$(sed -n '404p' "$file" | jq -r
'.timestamp // empty'); echo "Timestamp: $timestamp"; echo "Cutoff: $cutoff_date"; if [[ "$timestamp" > "$cutoff_date" ]]; then echo "PASSES"; else echo "FAILS"; fi)
⎿ Error: Exit code 1
(eval):1: parse error near `('
∴ Thinking…
Another bash tool error! LOL this is so ironic. Let me write it to a script.
⏺ LOL another bash tool error! Let me write a test script:
This example error (1 type of many) contains $(...) (command substitution) and [[ ]] (test construct), and has occurred many times for me, so perhaps it is one way to reproduce the error. Issue can be annoyingly worked around by instructing claude to not use the bash tool and instead write code to a script & run from disk; however, since this issue is so frequent for me, this issue slows me down significantly.
Environment 1 (macOS): Darwin 24.6.0, Terminal.app, Node v24.10, Claude Code v2.0.34, Model: claude-sonnet-4-5-20250929
Environment 2 (RHEL): RHEL 8.4 (Ootpa), Kernel 4.18.0-305.el8.x86_64, SSH, GNU bash 4.4.19(1)-release (x86_64-redhat-linux-gnu), Node v22.17, Claude Code v2.0.34, Model: claude-sonnet-4-5-20250929
EDIT: To clarify, when I run the command it says it is trying to run, it works perfectly. It is also identical in the script file it writes to disk, which also works. I am not sure why it errors so often when the code appears to be fine.
Additional Reproduction Case: Variable Expansion Fails in For Loop
I encountered a similar issue where variable expansion completely fails in a for loop when combined with certain commands.
Command Attempted
for pr_num in 1736 1729; do echo "=== PR #$pr_num ==="; gh pr view $pr_num --json body --jq '.body' 2>&1 | head -1; done
Expected Behavior
=== PR #1736 ===
(output from gh pr view 1736)
=== PR #1729 ===
(output from gh pr view 1729)
Actual Behavior
=== PR # ===
no pull requests found for branch "main"
=== PR # ===
no pull requests found for branch "main"
The variable $pr_num is not expanded in the echo command.
Trace Output (set -x)
When enabling command tracing with set -x, the actual executed commands reveal the issue:
+(eval):1> pr_num=1736
+(eval):1> echo '=== PR # ==='
+(eval):1> gh pr view ''
+(eval):1> head -1
+(eval):1> pr_num=1729
+(eval):1> echo '=== PR # ==='
+(eval):1> gh pr view ''
+(eval):1> head -1
Key observations:
- Loop variable assignment works correctly:
pr_num=1736 - Double quotes are converted to single quotes:
echo '=== PR # ==='instead ofecho "=== PR #$pr_num ===" - Variable passed to
gh pr viewbecomes empty string:gh pr view ''instead ofgh pr view 1736
Interesting Finding
The same for loop works correctly when simplified:
for pr_num in 1736 1729; do echo "PR #$pr_num"; done
Output:
PR #1736
PR #1729
The issue only appears when combining the for loop with certain commands like gh, jq, or complex pipelines.
Environment
- OS: Linux (WSL2)
- Shell: zsh (my default shell; Claude Code uses the user's default shell)
- Claude Code version: (latest as of 2025-11-14)
Note: This issue appears to affect multiple shells. The original report was from bash environments (macOS and RHEL), and I've reproduced the same behavior in my zsh environment. This suggests the problem lies in how the Bash tool processes command strings before passing them to the shell, rather than in the shell itself.
This trace output might help identify where the escaping/quoting transformation is occurring in the Bash tool implementation.
This issue should NOT be auto-closed as a duplicate.
The duplicate candidates (#3839, #1132, #4315) all describe the < /dev/null injection problem. However, this issue (#7387) is about a different problem: variable expansion failure and quote transformation.
Evidence from reproduction:
The issue is still reproducible as of Claude Code v2.0.55:
for pr_num in 123 456; do echo "=== PR #$pr_num ==="; echo "test" | head -1; done
Expected:
=== PR #123 ===
test
=== PR #456 ===
test
Actual:
=== PR # ===
test
=== PR # ===
test
The variable $pr_num is not expanded. This occurs when combining a for loop with a pipeline. The same loop without a pipeline works correctly.
This is a distinct bug from the < /dev/null injection issue and should be tracked separately.
This issue has been inactive for 30 days. If the issue is still occurring, please comment to let us know. Otherwise, this issue will be automatically closed in 30 days for housekeeping purposes.
This is indeed still very much an issue. It is rather annoying that you continually require assurances of this. It should be easy to see that there are many bug reports about this and related issues, and you should have plenty of ways to reproduce this yourselves.