Claude CodeのWindows Git Bashでコマンドが約8KBで切れる原因と回避策
WindowsのGit Bashで約8KBを超えるBashコマンドが途中で切れ、バックスラッシュも半分になる不具合の原因と、Writeツール経由・PowerShellツールでの回避策をまとめます。
WindowsでGit BashをBashツールのシェルに使っていると、長いコマンドが unexpected EOF while looking for matching で失敗することがあります。構文は正しいのに落ちるのが特徴です。原因はコマンドの中身ではなく、コマンドがbashへ渡る経路にあります。
GitHubのissue #93618と#93915には、同じ経路に起因する2つの症状が報告されています。約8KBを超えるとコマンドが途中で切れる問題と、連続したバックスラッシュが半分になる問題です。どちらもClaude Code側の修正待ちなので、当面はコマンドを長くしない運用で避けます。
約8KBを超えると何が起きるか
cat > file <<'EOF' のヒアドキュメントで大きな本文を書かせると、次のようなエラーで終了します。
/usr/bin/bash: -c: line 102: unexpected EOF while looking for matching `''エラーは構文の問題を指していますが、コマンドは壊れていません。#93915の報告者は、失敗した31件のコマンドを取り出して bash -n(構文チェックのみ)にかけ、30件が問題なく通ったと書いています。テキストは正しく、bashに届く前に切られていたわけです。
報告されているサイズ別の結果は次のとおりです。
| コマンドのサイズ | 成功 | 失敗 |
|---|---|---|
| 4KB未満 | 成功1,069 | 失敗0 |
| 4KB〜8KB | 成功77 | 失敗0 |
| 8KB〜32KB | 成功0 | 失敗31 |
| 約32KB超 | 成功0 | 失敗5(uv_spawn の ENAMETOOLONG) |
この集計は#93915の報告者が711セッション分のトランスクリプトから数えた値で、1つの環境の実測です。傾向として、4KBを下回るコマンドは影響を受けず、8KB付近が境界になっています。
なぜ切れるのか:bash -cとMSYS2のargv
Bashツールは、ユーザーのコマンドをそのまま実行するのではなく、シェルスナップショットの読み込みや環境変数の設定を前置した1本の文字列にまとめます。#93618では、おおよそ次の形だと説明されています。
bash -c "source <shell-snapshot> 2>/dev/null || true && export TEMP=... \
&& eval '<command>' < /dev/null && pwd -P >| <cwd-file>"この文字列がWindowsのコマンドライン引数としてGit Bash(MSYS2ランタイム)へ渡ります。#93915が引く上流の報告(msys2-runtime)によると、MSYS2はWin32のコマンドラインから引数を組み立て直す際に glob() を通します。glob() は固定の8192文字バッファで入力を変換するため、それより長い引数は切り詰められます。
glob() の経路に入る条件は、引数に ?*["'(){} のいずれかが含まれることです。シェルのワンライナーは引用符を含むので、ほぼ必ずこの経路に入ります。
WindowsのCreateProcess自体は約32,767文字まで許すため、Windows側の制限ではありません。#93915の計測では、同じMSYSランタイムの echo.exe は20,000文字、ネイティブの python.exe は32,000文字を受け取れました。詰まるのは bash -c だけです。
単引用符が予算を食う
ユーザーのコマンドは eval '...' の中に入るため、コマンド内の単引用符 ' は '"'"' の5文字に置き換わります。1文字が5文字になるので、実質の予算は見た目より早く尽きます。2つの報告の計測値は次のとおりです。
- #93618:予算は8175文字。単引用符1個につき約4文字分(4.003)を追加で消費し、二重引用符は消費0
- #93915:
bash -cの上限は8,203文字
2つの数字が食い違うのは、Claude Codeのバージョンとラッパーの長さ、Git Bashのバージョンが違うためと考えられます(#93618はClaude Code 2.1.263・MSYSランタイム3.6.6、#93915はMSYSランタイム3.6.9)。8,000文字前後を目安にしておくのが安全です。
英文の散文は won't や $(date '+%F') のように単引用符が多く、見た目より早く上限に届きます。1,000個の単引用符を含むコマンドなら、それだけで約4,000文字分が予算から消えます。
バックスラッシュが半分になる別の不具合
もう1つの症状は、サイズと無関係に起きます。#93618と#93915は、どちらもバックスラッシュの連続がbashへ届くまでに半減すると報告しています。
| 送ったもの | bashに届いたもの |
|---|---|
\\ | bashに届いたもの\ |
\\\\ | bashに届いたもの\\ |
C:\Users\name(単独の \) | bashに届いたものそのまま |
エラーは出ません。Pythonの正規表現 r'\\d+' が r'\d+' として書き込まれると、バックスラッシュではなく数字にマッチするコードになり、スクリプトは正常終了したまま誤った動作をします。#93618では、ファイルに書いた \r\n のエスケープが本物の改行になり、原因の特定に4回かかった例が挙がっています。
#93915の計測では、295バイトの小さなコマンドでも破損が出ました。そのため、ペイロードを分割しても、バックスラッシュの問題には効きません。
自分の環境で確かめる
#93618の再現手順は次のとおりです。引用符付きのヒアドキュメントなので、bashはバックスラッシュに触りません。
cat <<'EOF' | od -c
a\b c\\d e\\\\f
EOF期待値は a\b c\\d e\\\\f です。報告された実際の出力は a\b c\d e\\f で、連続部分がすべて半分になっています。同じコマンドをターミナルで直接実行して差が出るなら、原因はClaude Codeからbashへの受け渡しにあると切り分けられます。
回避策:ファイルに書いてから実行する
両方の症状は、コマンドをコマンドライン引数で渡すことから生じています。#93618は、Writeツールで本文をファイルに書き、そのファイルを実行する方法を確実な回避策として挙げています。WriteツールもPowerShellツールも、MSYS2の引数処理を通りません。
手順は3ステップです。
- Writeツールで本文をファイルに書く(ヒアドキュメントは使わない)
- Bashツールでは短いコマンドでファイルを実行する
- 実行後に必要なら一時ファイルを削除する
bash ./scripts/gen-report.shBashツールに渡るのはこの1行だけなので、サイズ制限にもバックスラッシュの半減にも当たりません。スクリプトの中身はWriteツールが書いたバイト列がそのまま保存されます。
Writeツールは、新規ファイルなら事前のReadなしで作れます。既存ファイルの上書きは、モデルによっては先にReadが要ります(Claude Opus 4.6やHaiku 4.5以前の世代は常に必要で、新しいモデルは条件付きで不要です)。
PowerShellツールに任せる選択肢
公式ドキュメントによると、WindowsのPowerShellツールはBashツールと別経路でコマンドを実行します。Git Bashを入れていないWindowsでは自動で有効になり、Git Bashがある環境でも、claude.aiとConsoleのアカウントでは既定でオンです。Bedrock・Google Cloud・Foundryのセッションで使うには、CLAUDE_CODE_USE_POWERSHELL_TOOL=1 を設定します。
{
"env": {
"CLAUDE_CODE_USE_POWERSHELL_TOOL": "1"
}
}有効にすると、Claudeは主なシェルとしてPowerShellを扱い、POSIXスクリプトが必要なときだけBashツールを使います。#93618は、PowerShellツールはこの問題の影響を受けないと報告しています。ただしPowerShellの構文で書き直す必要があり、プレビュー段階の制限(プロファイルが読み込まれない、Windowsではサンドボックス未対応)も公式に明記されています。
Git Bashの自動検出がうまくいかない環境の設定はscoopのGit Bashを指定する設定に、Git Bashを使わない構成はv2.1.120のリリースノートにあります。
効かない対処
issueに、試して失敗した方法が書かれています。
MSYS=noglobを設定する:bash -cの上限は8,203から32,731に上がります。しかし引用符のあるコマンドで引数の分割が壊れ、evalを使う経路では必ずunexpected EOFになります。#93618でも同じ理由で不採用です- コマンドを分割して送る:切り詰めは避けられますが、バックスラッシュの半減は295バイトでも起きるので直りません
- Base64にして渡す:それでも引数として渡るため、サイズが約33%増えて悪化します
- ヒアドキュメントの引用を書き換える:原因は構文でないため、効果がありません
長いコマンドをフックで止める
長いコマンドが通ってしまうと、失敗の理由が構文エラーに見えて時間を取られます。PreToolUseフックでBashのコマンド長を測れば、上限に届く前に止めて、Claudeへ「ファイルに書け」と伝えられます。フックは標準入力のJSONから tool_input.command を読み、終了コード2で呼び出しをブロックします。標準エラー出力の文言はブロックの理由として扱われます。
.claude/settings.json の設定例です。
{
"hooks": {
"PreToolUse": [
{
"matcher": "Bash",
"hooks": [
{
"type": "command",
"command": "${CLAUDE_PROJECT_DIR}/.claude/hooks/limit-bash-length.sh",
"args": []
}
]
}
]
}
}.claude/hooks/limit-bash-length.sh は、単引用符の膨張分を足した長さで判定する例です。しきい値の7000は、issueの実測(8175〜8203)から余裕を見た値で、公式の数字ではありません。
#!/bin/bash
# .claude/hooks/limit-bash-length.sh
COMMAND=$(jq -r '.tool_input.command')
QUOTES=$(printf '%s' "$COMMAND" | tr -cd "'" | wc -c)
SIZE=$(( ${#COMMAND} + QUOTES * 4 ))
if [ "$SIZE" -gt 7000 ]; then
echo "Bashコマンドが長すぎます(実効${SIZE}文字)。" >&2
echo "Writeツールでファイルに書き、bash <file> で実行してください。" >&2
exit 2
fichmod +x で実行権限を付けます。フックの標準入力の形と、終了コード2がPreToolUseの呼び出しをブロックする挙動は公式のhooksドキュメントに沿っています。このスクリプトが動くにはjqが要るため、Windowsでは導入状況を先に確かめてください。
CLAUDE.mdに書く規約
フックで止める前に、そもそも長いコマンドを書かせない方が手戻りは少なくなります。Windowsのプロジェクトでは、CLAUDE.md に次のような規約を置く方法があります。
## Windows Git Bashでのコマンド
- 2KBを超える本文や、バックスラッシュを含むスクリプトは、Bashのヒアドキュメントで
書かず、Writeツールでファイルにしてから `bash <file>` で実行する
- 正規表現やUNCパスなど `\\` を含む内容は、必ずWriteツール経由で保存する
- Bashで `unexpected EOF while looking for matching` が出たら、引用符を
書き換える前にコマンドの長さを疑う2KBという基準は、4KB未満は無傷という報告の実測より保守的に取った値です。バックスラッシュ入りの内容は、サイズに関係なくWriteツールに寄せるのが実態に合います。
ヒアドキュメントなど複数行コマンドの自動承認が効かない条件は、複数行コマンドの自動承認にまとめてあります。
出力の切り詰めとは別の問題
この記事で扱った切り詰めは、コマンドの入力側で起きます。Bashの出力が長すぎて切られる問題は別物で、BASH_MAX_OUTPUT_LENGTH で調整する話はBASH_MAX_OUTPUT_LENGTHの解説にあります。
修正の状況
#93618と#93915はどちらもopenのままで、提案されている修正方針は次の2つです。
- コマンドを標準入力(
bash -s)で渡す。#93915では259KBまで同一のバイト列で届いたと報告されています - 一時ファイルに書いて
bash <file>で実行する。引数の処理を通らないので、長さの制限とバックスラッシュの半減が同時に消えます
どちらも、コマンドを引数として渡すのをやめる方向です。#93618はさらに、上限を超えたときに構文エラーを装わず、明確なエラーを返すことも提案しています。
Claude Codeのchangelogを検索しても、この2件に対応する修正項目は見つかりません。修正が入るまでは、ファイルに書いてから実行する運用が実質的な対処です。
まとめ
Windows + Git Bashで、Bashツールのコマンドが約8KBで切れたり、バックスラッシュが半分になったりするのは、Claude Codeがコマンドを引数としてMSYS2のbashへ渡す経路が原因です。構文を疑ってヒアドキュメントの引用を書き換えても直りません。
回避の軸は3つです。長い本文はWriteツールでファイルにする、バックスラッシュを含む内容は大きさに関係なくファイル経由にする、Bashの代わりにPowerShellツールを使う。フックで実効長を測って止めれば、エラーの原因探しに時間を使わずに済みます。