「pkill Claude Code process」の意味 — Claude Code
Claude Codeがpkillを拒否する「pkill pattern matches the Claude Code process」は、自分自身を巻き込むパターンから会話を守るガードです。対処とmacOSとの違いを実機で示します。
Claude Codeに古いプロセスの掃除を頼んだら「pkill: refusing to run」と拒否された。この場合、コマンドの書き方が間違っているわけではありません。パターンがClaude Code自身のプロセスにも一致したため、実行前に止められています。実行していれば、会話が途中で強制終了しかねませんでした。
拒否されたとき、まず何をするか
Bashツールの結果に、次のメッセージが返ります。
pkill: refusing to run — this pattern matches the Claude CLI process (PID 12345).
Narrow the pattern, or target your own children with `pkill -P $$ ...`.エラーはBashツールの結果として返るだけで、ターミナルにバナーは出ません。Claude自身がたいていコマンドを直して再試行するため、気づかないうちに解決していることもあります。自分で直すなら、次の順で見ます。
拒否されたpkillの直し方
- 1
パターンを絞る
pkill -f nodeのような短い部分一致をやめ、対象バイナリのフルパスなど具体的な文字列に書き換えます。 - 2
対象が自分の子プロセスなら範囲を限定する
そのシェルが起動したプロセスだけを止めたいなら、
pkill -P $$ <パターン>にします。$$は現在のシェルのPIDで、その子プロセスだけが対象になります。 - 3
Linuxなのに拒否されない場合はバージョンを見る
v2.1.214より前のClaude Codeにはこのチェックがありません。
claude --versionで確かめ、古ければclaude updateで更新します。
なぜpkill -fが自分を巻き込むのか
-fは、プロセス名だけでなくコマンドライン全体にパターンを当てます。pkill -f nodeはnode server.jsだけでなく、コマンドラインのどこかにnodeを含むプロセスを全部拾います。Claude Code自身のプロセスのコマンドラインにパターンの文字列が含まれていれば、そのプロセスも一致します。-fで短い一般語を渡すほど、自分を含みやすくなります。
プロセス名の完全一致だけを対象にする-xや、フルパスまで書いたパターンなら、一致範囲は大きく狭まります。
| パターンの書き方 | 一致範囲 | 事故りやすさ |
|---|---|---|
pkill -f node | 一致範囲コマンドライン全体にnodeを含む全プロセス | 事故りやすさ高い(短い一般語はClaude Code自身にも一致することがある) |
pkill -f "node server.js" | 一致範囲コマンドラインにnode server.jsを含むプロセス | 事故りやすさ中程度 |
pkill -P $$ | 一致範囲現在のシェルの子プロセスのみ | 事故りやすさ低い(自分が起動した範囲に限定) |
pkill -P $$の動きは、Claude Codeの外で試せます。次のコマンドは、子プロセスとしてsleepを2つ起動し、pkill -Pで止めます(macOS上のv2.1.289で実行)。
bash -c 'sleep 4242 & sleep 4243 &
echo "children: $(pgrep -P $$ | wc -l)"
pkill -P $$ sleep; sleep 0.3
echo "left: $(pgrep -P $$ | wc -l)"'出力は次のとおりです。起動した2つのsleepだけが終了し、同じマシン上の他のプロセスには触れていません。
children: 2
bash: line 1: 85937 Terminated: 15 sleep 4242
bash: line 1: 85938 Terminated: 15 sleep 4243
left: 0拒否はどう判定されているか
Claude Codeはpkillの実行前に、同じパターンでpgrepを先に走らせます。結果に自分のプロセスIDが含まれていれば、pkill本体を実行せずに拒否します。被害を止めるのでなく、実行そのものを防ぐ作りです。
判定の材料になるのが環境変数CLAUDE_PIDです。Claude Codeは、起動するサブプロセス(BashツールとPowerShellツールのコマンド、hookコマンド)に自分のプロセスIDをこの変数で渡します。Linux上のBashツールのシェル統合が、この値と照らしてpkillのパターンを検査します。CLAUDE_PIDはv2.1.214以降で使えます。
実際に、Claude CodeのBashツールの中でecho $CLAUDE_PIDを実行すると、実行中のセッションのPIDが入っていました(macOS上のv2.1.289)。判定にはLinuxが必要ですが、変数そのものはmacOSでも渡されます。
実行前にpgrepで一致を確かめる
Claude Codeが内部でやっている確認は、自分の手でも再現できます。pkillの代わりにpgrep -flを同じパターンで走らせると、止まるプロセスのPIDとコマンドラインが一覧で出ます。
bash -c 'sleep 4242 & sleep 4243 &
pgrep -fl "sleep 424"
echo "--- narrowed:"
pgrep -fl "sleep 4242"
kill $(jobs -p)'macOS上のv2.1.289で実行した出力です。パターンをsleep 424にすると2件、sleep 4242まで書くと1件に絞れました。
42302 sleep 4242
42303 sleep 4243
--- narrowed:
42302 sleep 4242一覧に自分のセッションや無関係なサービスが混じるなら、そのパターンでpkillを打ってはいけません。pgrepの一覧が意図どおりの1件に収まってから、同じパターンをpkillに渡します。Claude Codeに掃除を頼むときは、「まずpgrep -flで一致を見せてから止めて」と伝えておく手もあります。
Linuxでだけ働くチェック
このガードが動くのはLinuxだけです。macOSではpkillが無修正のまま実行され、自分に一致するパターンでも拒否されません。
同じ`pkill -f`でも結果が分かれる
Linux
pgrepの事前チェックで自分のPIDが見つかると、実行前に拒否されます。会話は続きます。
macOS
pkillがそのまま実行されます。パターンがClaude Codeに一致すれば、セッションが巻き込まれます。
LinuxのCIで見つかった拒否が、手元のMacでは再現しないのはこのためです。エラー一覧が説明しているのはLinuxとmacOSで、Windowsでの挙動には触れていません。
自分の環境でガードが効くかを確かめる
拒否が出ない、あるいはCIでだけ出る場合は、OSとバージョンの2点で切り分けます。
uname -s
claude --version手元のMacでの出力は次のとおりです。
Darwin
2.1.289 (Claude Code)uname -sの結果 | claude --version | 起きること |
|---|---|---|
Linux | claude --versionv2.1.214以降 | 起きること一致するパターンは実行前に拒否される |
Linux | claude --versionv2.1.213以前 | 起きること拒否されず、一致すればセッションが終了する |
Darwin(macOS) | claude --versionどれでも | 起きること拒否は出ず、pkillが無修正で走る |
DockerイメージのLinuxコンテナでClaude Codeを固定バージョンで動かしているなら、この表の2行目に当たらないかを先に見ます。更新手順はclaude updateです。
v2.1.214より前の挙動
このチェックはv2.1.214(2026年7月18日リリース)で入りました。changelogには「pkill -fのパターンがCLI自身のプロセスに一致したとき、Bashツールがセッションを終了させる問題を修正した(Linux)」と書かれています。
バージョンを固定したCIランナーやコンテナがv2.1.213以前のままなら、同じ事故が起こりえます。
macOSにも同じ歯止めをhookで足す
組み込みのチェックがない環境でも、CLAUDE_PIDを使えば同じ検査をhookで書けます。hookコマンドにもCLAUDE_PIDが渡されるためです。PreToolUseのhookはBashツールの実行前に走り、終了コード2で呼び出しを拒否できます。
次のスクリプトは、コマンドからpkill -fのパターンを取り出し、pgrep -fの結果に$CLAUDE_PIDが含まれていれば拒否します。pkill -fの直後のパターンだけを拾う簡易版で、オプションの順序違いや-fxのような結合形には対応していません。パターンも最初の1語(sleep 4242ならsleep)までしか拾わないため、実際より広い範囲で検査し、誤って拒否する側に倒れます。
#!/bin/bash
cmd=$(jq -r .tool_input.command)
pat=$(printf '%s' "$cmd" | sed -nE 's/.*pkill +-f +"?([^" ;|&]+)"?.*/\1/p')
if [ -n "$pat" ] && pgrep -f "$pat" | grep -qx "$CLAUDE_PID"; then
echo "pkill -f \"$pat\" matches the Claude Code process (PID $CLAUDE_PID)" >&2
exit 2
fisettings.jsonには、Bashツールを対象にして登録します。
{
"hooks": {
"PreToolUse": [
{
"matcher": "Bash",
"hooks": [
{ "type": "command", "command": "\"$CLAUDE_PROJECT_DIR\"/.claude/hooks/guard-pkill.sh" }
]
}
]
}
}スクリプト単体の動作は、sleepプロセスのPIDをCLAUDE_PIDに見立てて確かめられます(macOS上で実行)。パターンsleepは一致して終了コード2、一致しないパターンは0でした。
pkill -f "sleep" matches the Claude Code process (PID 63547)
exit=2
exit=0スクリプトは.claude/hooks/guard-pkill.shに置き、chmod +xで実行権限を付けます。jqが入っていない環境では、先に導入が必要です。終了コード2のときに標準エラーへ出した文面は、Claudeにフィードバックとして渡るので、直し方を一言添えておくと再試行が早くなります。
似た仕組み: サブプロセスの環境変数スクラブ
Linuxには、pkillのガードとは別に、サブプロセスからホストのプロセスを見えなくする仕組みもあります。CLAUDE_CODE_SUBPROCESS_ENV_SCRUBを1にすると、サブプロセスの環境から認証情報が取り除かれます。Linuxでは加えて、Bashのサブプロセスが独立したPIDネームスペースで動きます。
目的は、プロンプトインジェクションでシェル展開から認証情報を読まれにくくすることです。取り除く対象は、変数名か値の形で判定されます。
| 変数の例 | スクラブの扱い |
|---|---|
ANTHROPIC_API_KEY、AWS_SECRET_ACCESS_KEY | スクラブの扱い削除する |
NPM_TOKEN、DB_PASSWORD | スクラブの扱い変数名が認証情報らしいので削除する |
パスワードを含むDATABASE_URL | スクラブの扱い値が認証情報らしいので削除する |
GITHUB_TOKEN、GH_TOKEN | スクラブの扱いghやGitHub APIを呼ぶスクリプトのため残す |
HTTP_PROXY、HTTPS_PROXY | スクラブの扱い残す |
副作用として、Linuxではps・pgrep・killがホストのプロセスを見ることも、シグナルを送ることもできなくなります。結果として、pkillが自分に一致する余地そのものがなくなります。GITHUB_TOKENが残る点は、GitHub Actionsのジョブに付けるpermissionsを絞る理由になります。
claude-code-actionは、allowed_non_write_usersを設定すると、この変数を自動で有効にします。関連するCLAUDE_CODE_SCRIPT_CAPSは、スクラブが有効なときに、特定スクリプトの呼び出し回数をセッションごとに制限します。{"deploy.sh": 2}と書くと、コマンドにdeploy.shを含む呼び出しが2回までになります。xargsやfind -execによる実行時の展開は数えられません。
権限ルールとの関係
settings.jsonのpermissions.denyにBash(pkill *)を書くのは、利用者が明示するルールです。pkillの拒否は、Bashツールが実行前にpgrepで確かめる別の検査で、パターンごとの設定を書いておく必要はありません。
似た発想の例が、rmやrmdirです。保護対象のパス(重要パス)を狙うと、どの許可ルールでも、PreToolUseフックの"allow"でも承認できません。権限設定がどうであれ、自分を巻き込むコマンドや破壊的すぎる操作は、別枠の仕組みで止まります。権限設計の全体はClaude Codeセキュリティ・権限ガイドに、settings.jsonの書き方はClaude Code settings.json完全ガイドにあります。
よくある質問
killでPIDを直接指定した場合も拒否されますか
エラー一覧が説明しているのはpkillだけです。PIDを直接渡すkillは、パターンで一致を探す命令ではないため、同じ検査の対象かどうかは別の話です。誤爆を避けるなら、$CLAUDE_PIDと一致しないことを自分のスクリプトで確かめてからkillを呼ぶ方法があります。
Bash(pkill *)をdenyに入れれば安全ですか
pkillの実行は確実に止まりますが、pkill -P $$のように安全な使い方まで一緒に使えなくなります。パターンの広さだけを見たいなら、前述のhookのように一致を調べてから拒否する書き方のほうが、止める範囲を狭くできます。
まとめ
拒否は「パターンが広すぎる」という合図で、フルパスかpkill -P $$に直せば通ります。Linuxで動かすCIやコンテナはv2.1.214以降かを確かめ、macOSでは自分でパターンを絞る前提で書くのが安全です。