claude-code icon indicating copy to clipboard operation
claude-code copied to clipboard

[BUG] Shell script occasionally fails due to crazy escaping

Open fsc-eriker opened this issue 4 months ago • 7 comments

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/null redirections is something I have seen in multiple bug reports, but see e.g. https://github.com/anthropics/claude-code/issues/4315

fsc-eriker avatar Sep 10 '25 06:09 fsc-eriker

Found 3 possible duplicate issues:

  1. https://github.com/anthropics/claude-code/issues/3839
  2. https://github.com/anthropics/claude-code/issues/1132
  3. 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

github-actions[bot] avatar Sep 10 '25 06:09 github-actions[bot]

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.

Buggy-McBugFace avatar Nov 06 '25 01:11 Buggy-McBugFace

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:

  1. Loop variable assignment works correctly: pr_num=1736
  2. Double quotes are converted to single quotes: echo '=== PR # ===' instead of echo "=== PR #$pr_num ==="
  3. Variable passed to gh pr view becomes empty string: gh pr view '' instead of gh 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.

skawaji avatar Nov 14 '25 02:11 skawaji

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.

skawaji avatar Nov 27 '25 08:11 skawaji

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.

github-actions[bot] avatar Dec 27 '25 10:12 github-actions[bot]

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.

fsc-eriker avatar Jan 07 '26 05:01 fsc-eriker