Claude Media
Claude Codeのamd64コンテナでgrepが動かない — Apple Siliconの回避策

Claude Codeのamd64コンテナでgrepが動かない — Apple Siliconの回避策

Apple Siliconのamd64コンテナで、Claude Code上のgrepとfindが「unknown option '-G'」で落ちる件。起きる条件、30秒の判定、arm64化とgrep直指定の回避策をまとめます。

Apple SiliconのMacでamd64のコンテナを動かし、その中でClaude Codeを使うと、grep や find が error: unknown option '-G' で失敗することがあります。ふだんのターミナルでは同じコマンドが通るため、原因が見えにくい症状です。原因はClaude Code側のシェル関数がプロセス名の受け渡しに頼っていることと、amd64のエミュレーション経路でその名前が消えることの組み合わせです。回避策は、コンテナをarm64で動かすか、検索コマンドの実体を直接指すかの二択になります。

何が起きるのか

エラーはClaude Code自身のシェルの中でだけ出ます。issue #84749の報告では、! で実行したコマンドが次のように失敗しています。

! grep -n 'pattern' somefile
error: unknown option '-G'
 
! find . -name '*.md'
error: unknown option '-S'

-G と -S は利用者が打ったものではありません。Claude Codeが注入するシェル関数が、検索コマンドの呼び出しに自分でフラグを足しています。そのため、見覚えのないオプションが「不明」と言われる形になります。

同じコマンドをコンテナの素のターミナルで打つと成功します。素のターミナルはClaude Codeのシェルスナップショットを読み込まないので、関数が定義されていないためです。「手元では動くのにClaude Codeの中でだけ動かない」という見え方は、この差から来ます。

なぜ検索コマンドが関数になっているのか

背景は、v2.1.117の変更にあります。macOSとLinuxのネイティブビルドでは、Glob と Grep のツールが、Bashツール経由で使える組み込みの bfs と ugrep に置き換えられました。ツール一覧の仕様でも、macOS・Linux・WSLでは両ツールが既定で外れており、Claudeは find と grep をBash経由で実行します。この2つのコマンドが、組み込み版の bfs と ugrep に向く仕組みです。

報告によれば、シェル関数は次のような形で組み込みバイナリを呼びます。

( exec -a ugrep "$_cc_bin" -G --ignore-files --hidden -I --exclude-dir=.git ... "$@" )

exec -a ugrep は、Claude Codeのバイナリを「ugrepという名前で」起動する指定です。バイナリは起動時の名前(argv[0])を見て、ugrepとして振る舞うか、bfsか、通常のCLIかを切り替えます。名前が届かなければ、通常のCLIとして -G を解釈しようとして、冒頭のエラーになります。

amd64コンテナで名前が消える理由

amd64のコンテナをApple Siliconで動かすと、amd64バイナリはRosetta 2などのエミュレータを介して実行されます。LinuxカーネルはこのときELFを直接実行せず、binfmt_misc に登録されたインタープリタ(エミュレータ)に渡します。

報告者の環境では、登録内容が interpreter /mnt/lima-rosetta/rosetta、flags: OCF でした。カーネルのドキュメントでは、呼び出し側が選んだ argv[0] をインタープリタに渡す指定は P フラグで、これが無いとその名前が失われます。報告者はこの点を、P 付きのハンドラで検証したわけではないと断っています。判定にはフラグを読むのでなく、次節のプローブを使うよう書かれています。

自分の環境のハンドラは、コンテナを動かしているVM側(ColimaやLimaならそのVMの中)で登録内容を読むと確かめられます。コンテナの中にもこのディレクトリはありますが、空です。

# コンテナではなく、コンテナを動かすVM側で実行する
cat /proc/sys/fs/binfmt_misc/*   # interpreter と flags の行を見る

バイナリは ARGV0 環境変数でも自分の役割を受け付けるため、そちらの経路は生きています。

経路arm64(ネイティブ)amd64(P なしのRosetta)
exec -a ugrep で名前を渡すarm64(ネイティブ)届くamd64(P なしのRosetta)届かない
ARGV0=ugrep で渡すarm64(ネイティブ)届くamd64(P なしのRosetta)届く

30秒で当たりか判定する

Claude Codeを入れる前に、コンテナだけで判定できます。報告にあるプローブは次のとおりです。

docker run --rm -it --platform linux/amd64 rockylinux:9 bash
# コンテナ内で
dnf install -y nodejs
echo 'console.log(process.argv0)' > a.js
( exec -a aaa node a.js )

process.argv0 は呼び出し側が渡した名前を返す値なので、名前が捨てられたかをそのまま見られます。

  • aaa と出れば、名前は届いています。この症状は起きません
  • /usr/bin/node と出れば、名前が捨てられています。該当します

同じ手順を --platform linux/arm64 で動かすと、同じマシンでも aaa と出るとのことです。

該当した環境にClaude Codeを入れたら、バイナリの役割切り替えを2通りで試せます。

CC=$(readlink -f "$(command -v claude)")
( exec -a ugrep "$CC" --version )   # 名前の経路
ARGV0=ugrep "$CC" --version         # 環境変数の経路

報告の環境では、1行目が 2.1.224 (Claude Code)(ugrepとして動いていない)、2行目が ugrep 7.5.0 ... でした。Claude Codeのシェルの中では、grep --version が ugrep で始まる行を返せば正常です。(Claude Code) と返るなら、名前の経路が死んでいます。

回避策1: コンテナをarm64で動かす

最も確実なのは、--platform linux/arm64 で動かすことです。エミュレーションを通らないので名前が届き、動作も速くなります。

docker run --rm -it --platform linux/arm64 <イメージ> bash

devcontainerやdocker composeで使っているなら、設定側でプラットフォームを固定します。

# docker-compose.yml
services:
  dev:
    image: <イメージ>
    platform: linux/arm64

devcontainer.json でイメージを直接指定している場合は、runArgs にフラグを足します。

{
  "image": "<イメージ>",
  "runArgs": ["--platform=linux/arm64"]
}

切り替える前に、イメージがarm64版を持つかを確かめられます。

docker buildx imagetools inspect <イメージ>
# Platform: linux/arm64 の行があれば選べる

arm64版が無い場合は選べません。イメージの作者に確認するか、自分でarm64向けにビルドし直す手もあります。社内のベースイメージがamd64専用だったり、依存するパッケージがamd64でしか配布されていなかったりする場合です。その場合は次の策になります。

回避策2: grepとfindの実体を指す

issueのコメントでも、修正が出るまでの対処は「/usr/bin/grep と /usr/bin/find を使わせるか、arm64で動かす」とされています。CLAUDE.mdに一行書くのが手軽です。

## 検索コマンド
このコンテナでは `grep` と `find` のシェル関数が壊れている。
検索には `/usr/bin/grep` と `/usr/bin/find` を絶対パスで使うこと。

この一行は、リポジトリ共有のCLAUDE.mdに入れるより、このコンテナ専用の置き場に分けるほうが影響を抑えられます。arm64の環境で同じ指示が残ると、速い組み込み版を使わなくなるためです。修正版が出たら、この節ごと削除して構いません。

Claudeはこの指示に従って、関数を経由しない実体を呼びます。ただし、コンテナ内に /usr/bin/grep が入っていることが前提です。issueによると rg も find・grep と同じ仕組みのシェル関数で包まれているので、rg を使わせる場合は実体のパスを別に指示する必要があります。実体のパスは、コンテナ内で command -v を使わずに確認します。関数が先に見つかってしまうためです。

ls -l /usr/bin/grep /usr/bin/find
type -t grep    # function と出れば関数が先に効いている

回避策3: GrepとGlobのツールを戻す

ツール一覧の仕様では、macOS・Linux・WSLでも、--tools か --allowedTools で Glob または Grep を名指しすると、両方のツールが戻ります。--allowedTools に名前を書くと両ツールが復活し、--tools では書いたものだけが戻ります。設定ファイルの許可ルールには、この効果がありません。

claude --allowedTools "Grep,Glob"

報告者は、このフラグを付けるとシェル関数が入らず、症状が出ないことを書いています。復活した Grep ツールがRosetta環境で動くかは、報告に書かれていません。実際に試すなら、このフラグで起動して検索を伴う依頼を1つ投げ、エラーが出ないかを見ます。うまくいかなければ、回避策1か2に戻ります。

回避策の比べ方

三つを、確実さ・前提条件・副作用で並べます。

回避策確実さ前提条件副作用
1. arm64で動かす確実さ高い(エミュレーションを通らない)前提条件イメージにarm64版がある副作用amd64専用の依存は動かせない
2. 実体のパスを指示する確実さ指示が守られる限り有効前提条件コンテナに /usr/bin/grep と /usr/bin/find がある副作用rg など他の関数は別に指示が要る
3. GrepとGlobのツールを戻す確実さ報告者の環境では症状が消えた。Rosetta環境での動作は未確認前提条件起動のたびにフラグを付ける副作用組み込み版に切り替えた変更を部分的に戻す

診断の落とし穴

報告者は、claude doctor が Search: OK (bundled) と表示する状態でも失敗すると指摘しています。この表示は組み込みバイナリの存在を見るだけで、実際に呼び出して成功するかまでは見ていない、という指摘です。コメントでも、健全性の確認では実際にバイナリを呼ぶべきだという点が認められています。doctor が通っても安心せず、grep --version をClaude Codeのシェルの中で打ってください。

切り分けの順番は次のとおりです。

  1. Claude Codeのシェルで grep --version を打ち、ugrep で始まる行が返れば正常で、ここで終わります
  2. (Claude Code) と返るなら、コンテナのCPUアーキテクチャを uname -m で見ます。x86_64 ならエミュレーション下です
  3. 前節のプローブで /usr/bin/node と出れば、名前が捨てられています。回避策1か2へ進みます
  4. arm64版のイメージが無いなら回避策2、あるなら回避策1です

もう1点、! のコマンドと、Bashツールの中のコマンドで経路が同じとは限りません。まず ! で再現するのが、報告の手順です。

修正はいつ出るのか

進み具合は、issue #84749のページで確かめられます。

issue #84749はopenのままで、修正版は出ていません。2026年8月25日には、Claude Codeの開発者がコメントで確認を済ませ、バグとして扱われています。

  • シェル関数は argv[0] で組み込みバイナリを選んでいる
  • 注入フラグだけで呼ぶと、報告どおりのエラーになる
  • ARGV0 環境変数の経路は、すでに動く
  • Rosetta側の挙動そのものは、検証環境の外なので直接は試せていない

提案されている直し方は2つです。関数を ARGV0 経由にするか、名前の経路が効いたかを検証して、だめなら素の grep に落とす方式です。同様の関数まわりの不具合は、Termux上でローダー経由で起動する環境でも別のissueとして出ています。ただし原因が違うので、そちらの回避策をこの症状に当てはめることはできません。

似た症状との見分け方

Macのコンテナまわりでは、症状が似ていても原因が別のものがあります。

症状当たる記事
unknown option '-G' / '-S' がClaude Codeのシェルでだけ出る当たる記事この記事(amd64のエミュレーション)
devcontainerで Unsupported platform: linux-arm64. No compatible Claude Code binary found. が出る当たる記事ColimaのdevcontainerでUnsupported platformが出るとき
.gitignore の対象ファイルが検索に出てこない当たる記事respectGitignoreの効く範囲

.gitignore の扱いは Glob と Grep で違い、設定の効き方にも差があります。検索が「失敗する」のでなく「見つからない」場合は、そちらを疑ってください。

まとめ

エラー文に出る -G と -S は利用者の入力ではなく、Claude Codeが注入したフラグです。amd64コンテナで起きるのは、エミュレーションが呼び出し時の名前を捨てるためで、環境変数の経路は生きています。プローブで当たりを判定し、arm64で動かせるなら動かす。動かせないなら、CLAUDE.mdで実体のパスを指示する。修正が入るまではこの二択です。

コンテナにプラグインやツールを組み込む構成の全体像は、Claude Codeプラグインのコンテナ事前展開にあります。

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