Claude Media
Claude CodeのGit BashでPATHが壊れlsもgrepも動かない原因と直し方

Claude CodeのGit BashでPATHが壊れlsもgrepも動かない原因と直し方

WindowsのGit BashでBashツールのls・grepが全部command not foundになる症状の確かめ方と、起動時のPATH取得がタイムアウトする原因、報告されている回避策を並べます。

WindowsのGit Bashで、Bashツールがlsもgrepもdateもcommand not foundと返す。echoのようなシェル組み込みだけは動く。この症状は、Claude Codeがセッション開始時に書き出すシェルスナップショットのPATHがWindows形式のまま壊れていることで起きる、と報告されています。同じマシンの別セッションは普通に動くので、気づきにくい不具合です。

この記事では、自分のセッションが該当するかの確かめ方、起動時のPATH取得がタイムアウトするという原因、壊れたセッションの立て直し方と再発を減らす設定を並べます。元になっているのは、anthropics/claude-codeのissue #99301(open)と、同じ見た目で別の経路から報告されている#72728(open)です。

症状は何で、どのPATHが壊れているのか

Claude Codeは、セッションごとに~/.claude/shell-snapshots/へsnapshot-bash-<ミリ秒時刻>-<ID>.shというファイルを作ります。Bashツールの各コマンドは、このスナップショットを読み込んでから実行されます。壊れるのは、その中のexport PATH=の1行です。

正常なスナップショットには、Git Bash向けのPOSIX形式のPATHが入ります。

export PATH='/c/Users/<user>/bin:/mingw64/bin:/usr/local/bin:/usr/bin:/bin:...'

壊れたスナップショットでは、Windowsのセミコロン区切りのPATHがそのまま書かれます。

export PATH='C:\WINDOWS\system32;C:\WINDOWS;...'

Git BashのPATHは:区切りです。Windows形式の各要素はC:の直後にも:があるため、コマンドの探索が成立しません。/usr/binも含まれないので、lsやgrepなどの外部コマンドが全部見つからなくなります。#99301の報告では、ls・grep・date・cut・head・trが失敗し、別の報告者はcatとpythonも失敗したと書いています。

セッションの途中で直らない点が厄介です。Bashツールは毎回このスナップショットを読み込むので、開始時に壊れたセッションは終わるまで壊れたままになります。

自分のセッションが該当するか確かめる

壊れたセッションでは外部コマンドが使えないため、確認はシェル組み込みだけで行います。まず現在のPATHを見ます。

echo "$PATH"

C:\Windows\system32;C:\Windows;...のように、ドライブ文字とバックスラッシュとセミコロンが並んでいれば、報告されている症状と一致します。

次に、最新のスナップショットのexport PATH=行を、組み込みだけで取り出します。ファイル名の時刻は13桁のミリ秒で桁数が揃っているので、グロブの並びの最後が最新です。

for f in ~/.claude/shell-snapshots/snapshot-bash-*.sh; do last=$f; done
while IFS= read -r line; do
  case $line in "export PATH="*) echo "$line";; esac
done < "$last"

この断片は、for・while read・case・echoだけで書いてあるので、PATHが空でも動きます。

壊れ方に傾向があるかを後から調べたいときは、#99301のコメントで共有されている集計スクリプトが使えます。各スナップショットについて、ファイルの更新時刻からファイル名のタイムスタンプを引いた生成時間を出し、PATHが壊れているかを判定します。~/.claude/shell-snapshotsに移動して実行するbashスクリプトで、正常なセッションから実行する前提です。

なぜ一部のセッションだけ壊れるのか

#99301の報告者は、同梱されているコード(v2.1.286)の挙動を次のように説明しています。

  1. スナップショットを書く前に、bash -lc 'echo "$PATH"'を10秒のタイムアウト付きで実行してPATHを取得する
  2. 終了コードが0で出力があったときだけ、その結果を使う
  3. 失敗やタイムアウトのときは、エラーを出さずにprocess.env.PATH(WindowsのPATHそのもの)を使い、変換せずに書き込む
  4. その後に追加される要素だけはPOSIX形式に変換される

壊れるのは、PATH取得が10秒に間に合わなかったときです。報告された数字は、この説明とよく合います。

報告環境壊れた数壊れたものの生成時間壊れていないものの生成時間
#99301本文環境v2.1.286、デスクトップアプリ壊れた数154件中12件壊れたものの生成時間13.4〜299秒壊れていないものの生成時間中央値2.2秒
コメント(VS Code拡張)環境Windows 11壊れた数件数の記載なし壊れたものの生成時間17.2〜42.1秒壊れていないものの生成時間6.1〜12.5秒
コメント(別のマシン)環境v2.1.295、デスクトップアプリ壊れた数46件中4件壊れたものの生成時間16.5〜40.5秒壊れていないものの生成時間1.5〜18.6秒(中央値2.5秒)

最後の行では、壊れていないスナップショットにも18.6秒かかったものが1件あります。生成時間が長いほど壊れやすい傾向は読み取れますが、10秒で線を引いたとき完全には分かれていません。この表の数値は、いずれも報告者が自分のマシンで測ったものです。

本文の報告者は、CPUが高負荷の状態でセッションを開く機会が多いと書いています。CPUが空いているときは、同じPATH取得が約0.6秒で終わり、POSIX形式のPATHが返ると述べています。別のマシンの報告者は、複数のセッションを並行して起動する使い方をしていると書いています。

同じバイナリで、16:07に始めたセッションは正常、17:35に始めたセッションは異常だったという記述もあります。バージョンの退行ではなく、起動時のタイミングで決まる不具合として扱われています。

壊れたセッションを立て直す

効果が報告されている順に並べます。

新しいセッションを開く

#99301の本文に書かれている回避策の1つ目です。マシンが空いているときに新しいセッションを始めれば、PATH取得が間に合って正常なスナップショットが作られます。壊れたセッション自体は直らないので、作業を引き継ぐ前提で切り替えます。

コマンドごとにPATHを補う

2つ目は、各コマンドの先頭でPATHを補う方法です。

export PATH="/usr/bin:/mingw64/bin:$PATH"; ls

スナップショットは毎回読み込み直されるため、この補完もコマンドごとに必要です。次のセッションまでの応急処置と考えるのが現実的です。

スナップショットの1行を手で直す

#72728の報告者は、実行中のセッションが読み込んでいるスナップショットのexport PATH=行を、cygpath -upで変換した値に書き換えると、そのプロセスが生きている間は直ったと書いています。Gitのusr/binをPATHの先頭に足す必要もあります。WindowsのPATHにはcoreutilsが含まれていないためです。

ただし、Bashツールでcygpathを呼ぶこと自体が壊れたセッションでは難しいので、絶対パスで呼ぶか、別のターミナルから編集することになります。

再発を減らす設定

.bashrcの重い処理を対話シェルだけにする

PATH取得はbash -lcで動くので、ログインシェルとして~/.bashrcなどを読み込みます。そこが遅いと、10秒の枠を食います。#99301のコメントの報告者は、次の2つが主な遅延要因だったと書いています。

  • Angular CLIの補完(source <(ng completion script))とdircolorsのeval
  • fnm env --use-on-cdによるcdのフック

補完や色設定は、対話シェルの判定で囲めます。

if [[ $- == *i* ]]; then
  source <(ng completion script)
fi

fnmは--use-on-cdを外した形(eval "$(fnm env --shell bash)")に変えたと報告されています。この対策で発生率は下がったものの、ゼロにはならなかったとのことです。

SessionStartフックでPATHを直す

同じコメントの報告者は、SessionStartフックを使った別の方法も紹介しています。公式のフックの説明では、CLAUDE_ENV_FILEに書いた内容は、各Bashコマンドの前に同じシェルで実行されます。そこでPATHがWindows形式なら変換する1行を書いておく、という案です。

#!/usr/bin/env bash
# SessionStartフック。Windows形式のPATHをPOSIX形式に直す
[ -n "$CLAUDE_ENV_FILE" ] || exit 0
echo 'case "$PATH" in *\;*) PATH="$(/usr/bin/cygpath -up "$PATH")" ;; esac' >> "$CLAUDE_ENV_FILE"
exit 0

~/.claude/settings.jsonには、このスクリプトを呼ぶフックを登録します。

{
  "hooks": {
    "SessionStart": [
      {
        "hooks": [
          { "type": "command", "command": "bash \"$HOME/.claude/hooks/session-env.sh\"" }
        ]
      }
    ]
  }
}

注意点が2つあります。

  • コメントのスクリプトは>で上書きしていますが、公式の例は>>で追記しています。他のフックが書いた変数を消さないよう、追記にしておくと安全です
  • 報告者自身が「should fix」と書いているとおり、この方法でPATHが直ることは確認済みの結果としては示されていません。コメントでは、フックが書いたPATHの追加がスナップショットのPATHの前に現れた、という観察までが述べられています

PreToolUseフックでスナップショットを書き換える

別のコメントでは、PreToolUseフック(Bashが対象)でスナップショットのexport PATH=行を書き換える案が出ています。フックがコマンドの実行前に走る点を利用したものです。投稿者は、セッションの最初の1回目でスナップショットがまだ無い場合は間に合わない可能性がある、と自分で注記しています。

効かなかった方法

#72728には、試して効果がなかった方法が並んでいます。

  • ~/.claude/settings.jsonのenvにPOSIX形式のPATHを設定する(他のキーは伝わるのにPATHだけはスナップショットが上書きする)
  • ~/.bashrcや~/.bash_profileでPATHを直す
  • BASH_ENVに修復スクリプトを指定する(環境変数は届くがスクリプトが読み込まれない)
  • アプリを再起動する(新しいスナップショットが同じ壊れたPATHで作られる)

最後の項目は、タイムアウトが原因の#99301とは様子が違います。#72728では再起動しても毎回壊れたと書かれており、PATH取得の遅さとの関係には触れていません。再起動しても毎回壊れる環境では、重い.bashrcの見直しよりも先に、こちらの報告を確認する価値があります。

同じcommand not foundでも別の原因

スナップショットのPATH行が原因の報告は、ほかにも過去にありました。#99301の「Related」には、次の3件が別の原因として挙がっています。いずれもクローズ済みです。

issue症状クローズの理由
#31799症状スナップショットのexport PATHにリテラルの$PATHが入り、システムのディレクトリが失われるクローズの理由not planned
#38951症状スナップショットの$PATHが展開されないクローズの理由not planned
#81356症状export PATHにプラグインのbinだけが入る(v2.1.204)クローズの理由not planned

見分ける手がかりは、スナップショットのexport PATH=行の形です。

行の形考えられる報告
C:\...;C:\...のようにWindows形式で;区切り考えられる報告#99301、#72728
$PATHという文字列がそのまま入っている考えられる報告#31799、#38951
プラグインのbinディレクトリだけが入っている考えられる報告#81356

3件はクローズ済みで、修正予定なしの扱いです。同じ型に当たったときは、issueを探す前にこの行の形で絞り込めます。

症状が似ていて別の問題もあります。claudeコマンド自体が見つからないのは、Claude Code本体のPATHの問題で、command not found: claudeが出たらPATHを通す手順で扱っています。コマンドは動くのに出力が空になる場合は、Git Bashで出力が空になる症状の切り分けが該当します。Git Bashの場所をClaude Codeに伝える設定が必要なら、scoopのGit Bashを使う設定から確認できます。

スナップショットの保管と掃除

壊れたスナップショットは、そのままディスクに残ります。shell-snapshots/はclaude project purgeの対象外です。この点は、.claudeディレクトリに残るデータの消し方にまとめてあります。

一方、changelogには、cleanupPeriodDaysによる保持期間の掃除が~/.claude/shell-snapshots/にも及ぶと書かれた項目があります。壊れた古いスナップショットを調べたい場合は、掃除される前に集計しておくと比較の材料になります。

現状と、確かめておきたいこと

#99301はopenで、コメントは3件です。報告されているバージョンはv2.1.286とv2.1.295で、デスクトップアプリのCodeタブとVS Code拡張で出ています。changelogを検索しても、シェルスナップショットのPATH取得を直したという項目はありません。

報告者が求めている修正の方向は、取得に失敗したときにWindows形式のPATHをそのまま書かないことです。具体的には、process.env.PATHをPOSIX形式に変換する、タイムアウトを延ばして再試行する、警告を出す、の3つが挙がっています。

手元で備えるなら、次の順で見るのが無駄が少なくなります。

  1. 症状が出たらecho "$PATH"でWindows形式かを確かめる
  2. Windows形式なら、新しいセッションを開く(応急処置はコマンドごとのPATH補完)
  3. ~/.bashrcの起動処理を見直し、補完や色設定は対話シェルだけに限定する
  4. 再起動しても毎回壊れるなら、#72728の症状かどうかを疑う

まとめ

lsもgrepも動かなくなるのは、Claude Code自体が壊れたからでなく、起動時のPATH取得が10秒に間に合わず、Windows形式のPATHがスナップショットに残ったためだと報告されています。一度壊れたセッションは終わるまで直らないので、見分けるのはスナップショットのexport PATH=行、直すのは新しいセッションが基本です。.bashrcの軽量化で頻度は下がりますが、ゼロにはならず、SessionStartフックでの修復は報告者自身も未確認の案という段階です。

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