mcpField
W
which

which

github.com/petr-korobeinikov開発171 回インストール3 日前に更新
リポジトリ

which について

whichは、コマンドの確認や解決に`which`ではなくPOSIXの`command -v`を使うよう案内する、シェル向けのエージェントスキルです。移植性の違いや置き換え方、パスを明示的に扱うケースを説明します。

主な機能

  1. 01コマンド確認を`command -v`に置換
  2. 02シェル間の移植性の違いを説明
  3. 03無出力とエラー表示の確認方法
  4. 04コマンド名とファイルパスを区別
  5. 05`$PATH`内の実行可能ファイル一覧に対応

活用シーン

  1. 01コマンドの利用可否を確認
  2. 02外部実行ファイルのパスを解決
  3. 03シェルコードやビルド手順を点検

インストール

コマンドをコピーしてターミナルで実行します。

$npx skills add https://github.com/petr-korobeinikov/skills --skill which

インストール後、Claude Code で/whichを入力して読み込まれたか確認します。

詳細

which

コマンドの有無を確認したり、そのパスを表示したりするために、whichは決して使わないでください。 代わりにcommand -vを使ってください。

理由

  • command -vはPOSIXで必須とされているシェル組み込みコマンドです (bash、zsh、dash、ash、ksh、busybox sh)。 whichは外部プログラムであり、 存在しない場合や、 エイリアスに置き換えられている場合、 またはシェル関数に置き換えられている場合があります。
  • whichの動作は実装によって異なります。 BSD、GNU、Debianのシェルスクリプト版which、zshの組み込み版、 busyboxのアプレットでは、 オプション、 出力形式、 終了コードが異なります。
  • command -vは、シェル組み込みコマンド、 関数、 エイリアスも報告します。 $PATH上のファイルだけではありません。 これは通常、呼び出し元が実際に求めている動作です。
  • command -vは、名前が見つからない場合に 信頼できるゼロ以外の終了コードを返し、 標準出力にも標準エラー出力にも何も出力しません。

直接置き換える場合

使わないでください代わりに使ってください
which foocommand -v foo
which foo >/dev/null 2>&1command -v foo >/dev/null
if which foo; then …if command -v foo >/dev/null; then …

名前が見つからない場合、command -vは標準エラー出力に何も書き込まないため、 2>&1は不要です。

1行で置き換えられず、以下のイディオムが必要なケースが2つあります。

  • path=$(which foo) — command -vはファイルシステム上のパスではなく、組み込みコマンド名やエイリアス文字列を返す場合があります。
  • which -a foo — command -vが解決するのは最初に見つかったものだけです。

イディオム

存在確認(出力なし):

if command -v foo >/dev/null; then
  # ...
fi

明確な失敗メッセージを表示する存在確認:

command -v foo >/dev/null || {
  echo "foo is required but not installed" >&2
  exit 1
}

ファイルシステム上のパスを解決する:

foo_path=$(command -v foo) || {
  echo "foo not found" >&2
  exit 1
}
case "$foo_path" in
  /*) ;;
  *)  echo "foo is not an external binary (got: $foo_path)" >&2
      exit 1 ;;
esac

command -vの出力は次のいずれかです。

  • /usr/bin/foo — $PATH上の外部ファイル。
  • foo — シェル組み込みコマンドまたは関数。
  • alias foo='…' — エイリアス。

/*のガードは最初の形式だけを受け入れます。

エッジケース

  • $PATH上のすべての一致を一覧表示する(which -a) ための、単一の呼び出しで済むPOSIX準拠の同等手段はありません。 $PATHを明示的に走査してください。

    ( IFS=:
      for dir in $PATH; do
        candidate=${dir:-.}/foo
        [ -f "$candidate" ] && [ -x "$candidate" ] && printf '%s\n' "$candidate"
      done )
    

    [ -f ]と[ -x ]を組み合わせると、通常の実行可能ファイルだけに絞り込めます。 これはwhich -aが報告する内容と一致します。 [ -x ]だけでは、実行ビットが設定されたディレクトリも受け入れてしまいます。

    bashおよびzshでは、type -a fooのほうが短く書けますが、 移植性はありません。

  • Makefile。 レシピは$(SHELL)を通して実行され、 デフォルトは/bin/shです。 プロジェクトがSHELLにPOSIX準拠ではないシェルを設定している場合は、 command -vを使う前に、レシピをPOSIXシェルに固定してください。 たとえば、SHELL := /bin/shとします。

適用範囲

このルールは、POSIXシェルとして記述または実行されるすべてのものに適用されます。 Bashツールの呼び出し、 SKILL.md/README.md内のスニペット、 scripts/配下のスクリプト、 Makefile、 CI設定、 Dockerfile、 インストール手順、 推奨される1行コマンドが対象です。

対象外: fish、 および内部でwhichをラップするツール (CMakeのfind_program、npm binなど)。

ファイルの編集中にwhichの呼び出しを見つけた場合は、 同じ編集の一環として、同等のcommand -v形式に置き換えてください。

コメント