Claude Media
Claude Codeのheredocが固まる原因 — macOSのHomebrew bashとの相性

Claude Codeのheredocが固まる原因 — macOSのHomebrew bashとの相性

macOSでHomebrewのbash 5.1以降がPATHの先頭にあると、500バイト超のheredoc書き込みが固まり、対象ファイルが空になることがあります。原因の切り分けと回避策をまとめます。

macOSでHomebrewのbash(5.1以降)をPATHの先頭に置いていると、Claude CodeのBashツールがcat > file <<'EOF'のheredocで書き込む場面で固まることがあります。目安は本文が約500バイトを超えるときです。Claudeが長めのファイルを書くたびに、120秒待たされたうえ、書き込み先のファイルが0バイトになります。

これはGitHubのissue #92262で報告されている症状です。issueはopenのままで、修正は入っていません。この記事では、報告の内容、自分の環境が当てはまるかの確認、今すぐ取れる回避策を順に説明します。

症状は「固まる」と「ファイルが空になる」の2つ

issueによると、書き込む内容が513バイトから65535バイトの範囲にあるとき、Bashツールの呼び出しがタイムアウトまで止まります。出力は1バイトも返りません。

厄介なのは2つ目の症状です。シェルはリダイレクトの時点で、書き込み先を先に切り詰めます。heredocの本文が届く前にコマンドが止まるので、既存のファイルが空のまま残ります。報告者は約2KBのmix.exsでこれに遭い、ファイルが空になって、heredocより後ろのコマンドも実行されなかったと書いています。

issueが示す再現条件は次のとおりです。

条件

issueが挙げる発症条件

  • OSと既定のbash

    macOSで、bash 5.1以降がPATHの先頭にある環境です。brew install bashの結果としてよくある状態です。

  • 本文のサイズ

    heredocの本文が513〜65535バイトのときだけ固まります。500バイト前後までと、64KB以上は通ります。

  • 本文の中身

    影響するのは総バイト数だけです。行数や内容は関係せず、heredocを使わない約1.9KBの1行コマンドは問題なく動いたと報告されています。

issueの環境は、Claude Code 2.1.260、macOS 26.5.2(arm64)、/opt/homebrew/bin/bashのGNU bash 5.3.15です。bash 5.3.9でも別のissueで同じ報告があるとされています。/bin/bash(3.2.57)では起きないと書かれています。

なぜ500バイトを境に固まるのか

issueの説明では、原因はClaude Codeではなく上流のbashにあります。

bash 5.1はheredocの実装を一時ファイル方式からパイプ方式に変えました。一時ファイルに戻るのは65536バイト以上のときだけです。これはLinuxの既定のパイプ容量に合わせた値です。

一方、issueはmacOSのPIPE_BUFが512バイトであることを根拠に挙げています(報告者はgetconf PIPE_BUF /が512を返すことを確認しています)。bashは本文をパイプに書き込み、満杯になるとそこでブロックします。ところが本文を読み出す子プロセスは、まだ生成されていません。誰も読まないパイプを待ち続けるデッドロックです。

bashを経由しないスクリプトファイルの直接実行でも、同じ結果が出たそうです。

bash400B600B〜20KB100KB
Homebrew 5.3.15400B完了600B〜20KB固まる100KB完了
/bin/bash 3.2.57400B完了600B〜20KB完了100KB完了

境目が両側にあるのは、小さい本文はパイプに収まり、大きい本文は一時ファイル経由になるためです。固まるのは中間の帯だけです。

Claude Code側で症状が悪化する3つの条件

issueは、デッドロックをデータ損失にまで広げているClaude Code側の挙動を3つ挙げています。

  1. BashツールがPATHで見つかったbashを選び、Homebrew版を使ってしまう
  2. 書き込み先が先に切り詰められるため、失敗した書き込みが既存ファイルを壊す
  3. auto modeとbypass-permissions modeが、ファイル書き込みにWriteツールよりheredocを勧める(auto modeの挙動も参照)

3つ目は、issue本文によると、モデルへのこの種の指示が別のissue(#92178など)で指摘されているという話です。つまり、macOSでHomebrewのbashを入れている人ほど、ファイルを大きく書く依頼でこの罠に当たりやすくなります。

自分の環境が当てはまるか確かめる

まず、シェルから見えるbashとそのバージョンを調べます。

which -a bash
bash --version | head -1
getconf PIPE_BUF /

which -a bashの先頭が/opt/homebrew/bin/bash(Intel Macなら/usr/local/bin/bash)で、バージョンが5.1以上なら、PATHの先頭は影響を受ける側です。PIPE_BUFが512なら、issueと同じ前提です。PATHの並びはインストール方法でも変わります。ネイティブ版とHomebrew版の違いはClaude CodeのMacインストール手順で扱っています。

ただし、Claude Codeが実際にそのbashを使うとは限りません。公式のenv-vars解説では、Bashツールのシェルは次の順で決まります。

  • CLAUDE_CODE_SHELLが動作するbashかzshを指していれば、それを使う
  • 未設定なら、$SHELLがbashかzshのとき、それを使う
  • それ以外は、PATH上や標準の場所にある最初の動作するzsh、次にbashを選ぶ

Bashツールが使うシェルが想定外の環境でどうなるかは、Claude CodeでNushellは使えるかが参考になります。

macOSの既定のログインシェルはzshなので、この解説どおりなら$SHELLのzshが選ばれ、問題は出ないはずです。issueは$SHELLの値に触れていません。ログインシェルをHomebrewのbashに変えている場合や、CLAUDE_CODE_SHELLで指定している場合は、確実に当たる側です。

推測で決めず、実際に選ばれたシェルを確かめるには、Claudeに次のコマンドをBashツールで実行させます。

Bashツールで echo "$BASH_VERSION" と ps -p $$ -o comm= を実行して、出力をそのまま見せて

$BASH_VERSIONが空ならzsh上で動いています。5.3.15(1)-releaseのような値なら、影響を受ける側のbashです。

回避策 — シェルの固定・本文サイズ・Writeツール

どれもissueが挙げた方法か、公式の環境変数の仕様から導ける方法です。

1. CLAUDE_CODE_SHELLで/bin/bashを指定する

CLAUDE_CODE_SHELLは、Bashツールのコマンドを実行するシェルを指定する環境変数です。bashかzshのパスを受け付け、動作しないパスは無視されて自動検出に戻ります。settings.jsonのenvに書けば、起動のたびに設定する必要はありません。

{
  "env": {
    "CLAUDE_CODE_SHELL": "/bin/bash"
  }
}

この方法は、issueが提案する「/bin/bashを明示して呼ぶ」を、利用者の側で実現するものです。注意点が1つあります。公式の説明では、Claude Codeは起動時に~/.bashrcなどを読み込んでエイリアスやシェル関数を取り込みます。bashを3.2に切り替えると、~/.bashrcに5.x専用の記法があれば、そこで警告が出るかもしれません。切り替えたら、よく使うコマンドが動くかを一通り試してください。

2. 本文を512バイト以下に収める

発症しない帯は、約500バイトまでと64KB以上です。長いファイルを分割して追記する方法でも、各heredocを小さくできます。ただし、書き込むたびにバイト数を気にするのは現実的ではありません。1つ目の回避策が使えないときの次善策です。

3. 書き込みをWriteツールに寄せる

CLAUDE.mdに、ファイルの作成と上書きにはheredocでなくWriteツールを使う、と書いておく方法があります。次のような短い規約で十分です。

## ファイル書き込み
- 新規作成と全体の上書きには、Bashのheredocではなく Write ツールを使う
- Bashで書くのは、1行で済む追記やリダイレクトだけにする

auto modeではモデルがheredocを選びやすいと報告されているため、明文化しておく意味があります。ただし、モデルが規約を常に守る保証はありません。シェルの固定と併用すれば、規約が守られなかった場合も止まらずに済みます。

issueは、shopt -s compat44でbash 5.1以前の一時ファイル方式に戻せると書いています。報告者の環境では解決を確認済みです。一方で、compatレベルの文書化されていない副作用に頼る方法でもあります。Claude Codeがシェルを起動する時点で設定できる場面は限られるため、ここでは紹介にとどめます。

タイムアウトを延ばしても解決しない

固まるのが120秒だと分かると、BASH_DEFAULT_TIMEOUT_MSを短くするか長くしたくなります。公式の仕様では、フォアグラウンドのBashコマンドのタイムアウトは既定で120000ミリ秒です。

ただし、デッドロックは時間では解けません。変わるのは待たされる長さだけで、ファイルが空になる点は同じです。タイムアウトの仕組みはBASH_DEFAULT_TIMEOUT_MSの解説にまとめています。

空になったファイルの復旧

切り詰められた内容はシェルのゴミ箱に移るわけではないため、復旧の頼りになるのは、gitなどのバージョン管理か、エディタ、Time Machineのバックアップです。

事前に備えておくこと

  • 上書きを任せる前に、変更をコミットまたはスタッシュしておく
  • 未追跡のファイルを含む作業では、Claudeに書かせる前にコピーを取る
  • 症状が出たら、まずgit statusで空になったファイルを確認し、git restoreで戻す

まとめ

macOSでHomebrewのbashが選ばれていると、約500バイトを超えるheredocがパイプ容量の壁にぶつかります。症状は120秒の停止と、書き込み先が空になることです。原因は上流のbashで、Claude Code側にも修正の提案が上がっています。

実際に自分の環境で起きるかは、echo "$BASH_VERSION"で選ばれたシェルを確かめるのが近道です。当たっていたら、CLAUDE_CODE_SHELLで/bin/bashを指定するのが、issueの提案にも沿う回避策です。併せて、上書きの前にコミットしておけば、被害は戻せる範囲に収まります。

この記事を共有:XはてブLinkedIn