「which」を使わないのはなぜですか?それでは何を使うべきですか?

「which」を使わないのはなぜですか?それでは何を使うべきですか?

実行可能ファイルへのパスを見つけたり、Unixシェルにコマンド名を入力したりすると、何が起こるのかを判断するためのさまざまなユーティリティ(、、、、、など)がwhichあります。typecommandwhencewherewhereiswhatishash

which私たちはこれを避けるべきだと言うことをよく聞きます。なぜ?代わりに何を使うべきですか?

答え1

あなたが知りたくないと思ったことはすべて次のとおりです。

一般化する

Bourneに似たシェルスクリプトから実行可能ファイルのパス名を取得するには(いくつかの注意事項があります、以下を参照)。

ls=$(command -v ls)

特定のコマンドが存在することを確認するには、次のようにします。

if command -v given-command > /dev/null; then
  echo given-command is available
else
  echo given-command is not available
fi

Bourneのような対話型シェルのプロンプトで:

type ls

このwhichコマンドはCシェルの破壊的な遺産であり、Bourneのようなシェルに単独で置くのが最善です。

はい

この情報をスクリプトの一部として見つけることと、シェルプロンプトで対話的に見つけることには違いがあります。

シェルプロンプトで一般的なユースケースは次のとおりです。このコマンドは奇妙に動作します。正しいコマンドを使用していますか?私がこれを入力している間、一体何が起こっているのでしょうかmycmd?どんな内容なのか、もう少し詳しく調べてもいいですか?

この場合、実際にコマンドを呼び出すよりも、コマンドが呼び出されたときにシェルが何をするのかを知りたいです。

シェルスクリプトではかなり異なる傾向があります。シェルスクリプトで単にコマンドを実行したい場合は、コマンドがどこにあるのか、何かを知りたい理由はありません。一般的に知りたいのは実行可能ファイルへのパスであるため、そのファイルからより多くの情報を取得できます(たとえば、そのファイルに関連する他のファイルのパスまたはそのパス情報から実行可能ファイルの内容を読み取ることができます)。

インタラクティブな方法で次のことを知りたい場合もあります。みんなmy-cmdこのように、システム(スクリプト)で使用できるコマンドはほとんどありません。

利用可能なほとんどのツール(しばしばそのような場合)は、対話型で使用するように設計されています。

歴史

まず、少しの歴史です。

1970年代後半まで、初期のUnixシェルには機能やエイリアスはありませんでした。エイリアスは1978年頃に導入されました(最初に紹介されましたが$PATH)。cshcsh解放、1979年2BSD5月).cshrcカスタムシェルに対しても処理されます(たとえば、各シェルはcshスクリプト.cshrcのようにインタラクティブでない場合も読み取られます)。

rcBourneシェルは1979年初頭にUnix V7で初めてリリースされましたが、機能サポートははるかに後で追加されました(1984年SVR2で)、いずれの場合もいくつかのファイルがありませんでした(.profile非シェル環境設定用)それ自体)。

cshインタラクティブな使用に便利で、より多くの機能を追加するため、Bourneシェルよりも人気があります(構文はBourneシェルよりはるかに悪いです)。

3BSD(1980)ではwhichcshスクリプトcshユーザーが実行可能ファイルを識別するのを助けるために追加されたこのスクリプトwhichは、今日多くの市販のUnices(Solaris、HP / UX、AIX、またはTru64など)で見つけることができるスクリプトとほとんど変わりません。

スクリプトは、ユーザーのコマンド~/.cshrc(呼び出しを使用しない限り、すべてのスクリプトと同様)を読み取り、エイリアスリストとcsh(保持されている配列に基づいて)csh -f提供されたコマンド名を探します。$pathcsh$PATH

ここにあります:which最初のものは当時最も人気のあるシェルでした(csh90年代半ばまでまだ人気がありました)、これが本に書かれていて広く使われている主な理由です。

cshユーザーにとっても、whichcshスクリプトが必ずしも正しい情報を提供するわけではありません。~/.cshrc後でプロンプトで定義したり、source別のファイルを指定してエイリアスをインポートしたりするのではなく、で定義されたエイリアスをインポートしcsh(良い考えではありませんが)、PATH再定義することができます~/.cshrc

whichBourne シェルでコマンドを実行すると、 で定義されたエイリアスを探すことができますが、~/.cshrcエイリアスを使用せずにエイリアスがない場合cshでも正しい答えを得ることができます。

1984年になると、組み込みコマンドによりSVR2のBourneシェルに同様の機能が追加されましたtype。 (外部スクリプトではなく)組み込まれているという事実はできるシェルの内部にアクセスできるので、正しい情報(ある程度)を提供します。

初期コマンドは、コマンドが見つからない場合に失敗した終了状態を返さないという点で、typeスクリプトと同様の問題を経験しました。また、実行ファイルの場合は、代わりに同様のものを出力するのwhichとは異なり、スクリプトで使用するのは簡単ではありません。whichls is /bin/ls/bin/ls

Unixバージョン8(一般には公開されていません)のBourneシェルに組み込まれている関数のtype名前が変更され、whatis引数と印刷関数の定義も報告するように拡張されました。また、type名前が見つからないときに失敗が返されない問題を解決します。

rc、Plan9(ワンタイムUnix以降)シェル(およびakangaなどの派生製品eswhatisも使用できます。

sh80年代半ばに開発されたが、1988年以前には広く使用されていなかったKornシェル(POSIX定義の基礎となるサブセット)cshは、Bourneシェルの上に多くの機能(ラインエディタ、エイリアス...)を追加しました。これには、いくつかのオプション(同様に詳細な出力を提供し、実行可能ファイルのみを検索(別名/関数の代わりに...))を使用する独自の組み込みwhence関数()が追加されます。type-vtype-p

AT&TとBerkeleyとの著作権紛争と同時に一部フリーソフトウェアシェルの実装は1980年代後半と1990年代初頭に登場しました。 Almquistシェル(BSDのBourneシェルに代わるもの)ash(FSFスポンサー)のすべてのパブリックドメインの実装は、1989年から1991年の間に登場しました。kshpdkshbashzsh

AshはBourneシェルを置き換えることを意図していましたが、typeずっと後で(NetBSD 1.3とFreeBSD 2.3で)組み込み機能はありませんでしたhash -v。ただし、OSF / 1にはOSFまで常に0を返す組み込み機能が/bin/shありました。type/ 1 v3.x。bash何も追加されていませんが、パス( like )とレポートを印刷するオプションがwhence追加されました。-ptypetype -pwhence -p-aみんな一致するコマンド。 s -likeコマンドがtcsh組み込まれてwhich追加されました。すべて。wherebashtype -azsh

Shell fish(2005)では、コマンドがtype関数として実装されています。

同時に、cshスクリプトはwhichNetBSDから削除され(tcshに組み込まれていて他のシェルではあまり使用されていないため)、機能が追加されました(呼び出されたwhereisとき)。 OpenBSDとFreeBSDではこれもCで書かれています。whichwhereiswhich$PATHwhich$PATH

実装する

さまざまな Unices には、コマンドの数十種類の構文とwhich動作の実装があります。

tcshLinuxでは、(およびの組み込み実装に加えてzsh)いくつかの実装を見つけることができます。たとえば、最近のDebianシステムでは$PATH

busyboxコマンドがもう1つありますwhich

一つは、GNU whichおそらく最も豪華なものです。 cshスクリプトの機能をwhich別のシェルに拡張しようとします。エイリアスと機能が何であるかを知ることで、より良い回答を提供できます(一部のLinuxディストリビューションでは、これにグローバルエイリアスが設定されていると思いますbash)。

zshいくつかあります。オペレーター実行可能ファイルのパスに展開されます。= ファイル名拡張子演算子と:c履歴拡張修飾子(ここでは次に適用されます)パラメータ拡張):

$ print -r -- =ls
/bin/ls
$ cmd=ls; print -r -- $cmd:c
/bin/ls

zshzsh/parametersコマンドハッシュテーブルは、モジュールのcommands連想配列としても使用されます。

$ print -r -- $commands[ls]
/bin/ls

このユーティリティ(Unix V8 BourneシェルまたはPlan 9 /のユーティリティをwhatis除く)は、ドキュメント(greps Whatisデータベース、つまりマニュアルページの概要)にのみ使用されるため、実際には関係ありません。rces

whereis3BSD実行可能ファイル、マニュアルページ、ソースコードを同時に見つけるために使用されるのではなく、現在の環境に基づいていないで、まるで作成されたかのようにwhich同時に追加されます。繰り返しますが、これは他の要件を満たしています。Ccsh

標準の点では、POSIXはcommand -vand-Vコマンド(POSIX.2008までオプション)を指定します。 UNIX指定typeコマンド(オプションなし)それはすべてです(where、、、whichwhenceどの標準でも指定されていません)。

一部のバージョンまではtypecommand -vLinux Standard Baseの仕様ではオプションでした。これは、たとえば、いくつかの以前のバージョンposh(両方に基づいているにもかかわらずpdksh)がどちらもない理由を説明します。command -v一部のBourneシェル実装にも追加されました(例:Solaris)。

今日の状態

現状はtypeBourneのようなすべてのシェルに共通です。 (@jarnoが指摘したように、以下の説明の「POSIXモードではないとき」またはAlmquistの一部の子孫のcommand -v警告/エラーに注意してください。シェル)。使用したい唯一のシェルです(そこにはシェルがなく、組み込まれているからです)。bashtcshwhichtypewhich

tcshシェルの外側のシェルでは、シェルzsh起動whichファイルの1つまたは一部に同じ名前のエイリアスまたは関数がなく、それに対して定義されたエイリアスまたは関数がない限り、~/.cshrcこれは~/.bashrcユーザーに通知することも、そうでない場合もあります。間違ったことを教えてください。$PATH~/.cshrc

特定の名前のすべてのコマンドを知りたい場合は、移植可能なものはありません。whereintcshまたは inzshまたは in ksh93 およびその他のシェルを使用でき、それらを組み合わせることができます。type -abashzshwhence -atypewhich -a

提案

実行可能ファイルのパス名を取得します。

スクリプトから実行可能ファイルのパス名を取得するには、いくつかの考慮事項があります。

ls=$(command -v ls)

標準的なアプローチになります。

しかし、いくつかの問題があります。

  • 実行ファイルを実行しないと、そのパスを知ることはできません。すべてtype、、、 ...経験的whichcommand -v方法を使用してパスを見つけます。コンポーネントを繰り返して、$PATH実行権限を持つディレクトリではなく最初のファイルを見つけます。ただし、シェルによっては、多くのコマンド(Bourne、AT&T ksh、zsh、ash...)は、システムコールがエラーを返さない$PATHまで順番に実行されます。execveたとえば、含まれていて$PATH実行/foo:/barしたい場合はls最初に実行を試み、/foo/lsそれ以外の場合は失敗します/bar/ls/foo/ls実行権限がないため、実行は失敗する可能性がありますが、有効な実行ファイルではないなど、さまざまな理由で実行が失敗する可能性があります。実行権限があるかどうかcommand -v lsを報告しますが、/foo/ls有効な実行ファイルではない場合は、/foo/ls実行がls実際に実行される可能性があります。/bar/ls/foo/ls
  • foo組み込み関数、関数、またはエイリアスかどうかを返しcommand -v fooますfoo。またはashなどの一部のシェルでは、pdksh空の文字列が含まれ、現在のディレクトリに実行可能ファイルが含まれている場合にzsh返されることがあります。場合によっては、これを考慮する必要があります。組み込み関数のリストは、シェルの実装(時にはbusyboxの組み込み関数)によって異なります。たとえば、環境で関数を取得できることを覚えておいてください。foo$PATHfoomountshbash
  • $PATH相対パスコンポーネントが含まれている場合(通常.または両方の現在のディレクトリを参照しますが、何でもできる空の文字列)、シェルによっては絶対パスがcommand -v cmd出力されないことがあります。したがって、走行中に得られた経路は、command -v他の場所に到達した後、もはや有効ではありません。cd
  • エピソード:ksh93シェルを使用している場合/opt/ast/bin(正確なパスはシステムによって異なる可能性があると思いますが)、$PATHksh93は追加の組み込み機能(chmod、、、cmp... cat)を提供しますが、そのパスが存在しない場合command -v chmodでも/opt/ast/bin/chmod存在しないものを返しますします。

コマンドが存在することを確認する

特定のコマンドが標準として存在することを確認するには、次のようにします。

if command -v given-command > /dev/null 2>&1; then
  echo given-command is available
else
  echo given-command is not available
fi

人々が使いたい場所which

(t)csh

cshと ではtcsh選択の余地は多くありません。ではこれが内蔵されているtcshので良いです。whichこれはcshシステムwhichコマンドであり、場合によっては目的の操作を実行できない場合があります。

特定のシェルでのみコマンドを検索する

これを使用するのが合理的である可能性がある状況は、シェルスクリプトで潜在的なシェル組み込み機能や関数を無視してコマンドのパスをwhich知りたい場合ですbashcshつまり、(例:または)、(例:、、)、(、)、またはシステムで使用でき、スクリプトではなく組み込み関数(例:または)です。tcshdashBournewhence -pkshzshcommand -evyashwhatis -prcakangawhichtcshzshwhichcsh

これらの条件が満たされると、以下が実行される。

echo=$(which echo)

echoシェルが組み込み/エイリアス/関数であるかどうかに$PATHかかわらず(極端な場合を除く)最初の項目へのパスを提供します。echo

他のシェルでは、以下を好みます。

  • 扱いにくいecho==echoまたはecho=$commands[echo]またはecho=${${:-echo}:c}
  • 変化の多く扱いにくい:echo=$(whence -p echo)
  • ヤッシュ:echo=$(command -ev echo)
  • RCアカンガ:(echo=`whatis -p echo`空白のあるパスを参照してください)
  • :set echo (type -fp echo)

やりたいことがあれば走るこのechoコマンドを使用すると、パスをインポートすることなく次のようにできます。

env echo this is not echoed by the builtin echo

tcshたとえば、組み込み関数の使用を防ぐには、を使用します。which

set Echo = "`env which echo`"

本当に外部コマンドが必要なとき

使用したい別の状況whichは実際には必要外部コマンド。 POSIXでは、すべてのシェル組み込みコマンド(たとえば)を外部コマンドとしても使用できるはずですが、残念ながら多くのシステムではcommandそうではありません。たとえば、このコマンドはLinuxベースのオペレーティングシステムではほとんど見つかりませんが、ほとんどcommandのオペレーティングシステムでは使用できます(オペレーティングシステムごとにオプションと動作が異なります)。commandwhich

外部コマンドが必要な状況は、POSIXシェルを呼び出さずにコマンドを実行したい場合です。

system("some command line")Cまたはさまざまな言語、...関数はpopen()シェルを呼び出してコマンドラインを解析するので、system("command -v my-cmd")その中で作業します。 1つの例外は、perlシェルにシェル特殊文字(スペースを除く)が表示されない場合、シェルが最適化されることです。これはバックティック演算子でも機能します。

$ perl -le 'print system "command -v emacs"'
-1
$ perl -le 'print system ":;command -v emacs"'
/usr/bin/emacs
0

$ perl -e 'print `command -v emacs`'
$ perl -e 'print `:;command -v emacs`'
/usr/bin/emacs

:;上記を追加すると、perlシェルが強制的に呼び出されます。を使用すると、whichこのトリックを使用する必要はありません。

答え2

人々がそれを使いたくない理由はwhichすでに説明されていますが、実際に失敗したシステムのいくつかの例は次のとおりですwhich

Bourneのようなシェルはwhich出力と出力を比較しますtypetypeシェルの組み込みとしてコマンドを呼び出す方法を知らせるシェルであるため、これは真でなければなりません)。

多くの場合、コーナーしかし、覚えておいてくださいwhich/typeしばしば極端な場合に使用されます(予期しない動作に対する答えを見つけるために、例:このコマンドはなぜこのように機能し、どのコマンドを呼び出すのですか?)。

ほとんどのシステム、ほとんどのBourne同様のシェル:機能

最も明確なケースは関数です。

$ type ls
ls is a function
ls ()
{
[ -t 1 ] && set -- -F "$@";
command ls "$@"
}
$ which ls
/bin/ls

その理由は、which実行ファイルと時にはエイリアスに関する情報だけが報告されるからです(常にそうではありませんが)。あなたのシェル)、関数ではありません。

GNUのマニュアルページには、関数の報告に使用する方法の壊れた(引用符を忘れたため$@)例がありますが、エイリアスと同様にシェルパーサーを実装していないため、だまされやすいです。

$ which() { (alias; declare -f) | /usr/bin/which --tty-only --read-alias --read-functions --show-tilde --show-dot "$@";}
$ f() { echo $'\n}\ng ()\n{ echo bar;\n}\n' >> ~/foo; }
$ type f
f is a function
f ()
{
echo '
}
g ()
{ echo bar;
}
' >> ~/foo
}
$ type g
bash: type: g: not found
$ which f
f ()
{
echo '
}
$ which g
g ()
{ echo bar;
}

ほとんどのシステム、ほとんどのBourne同様のシェル:組み込み

別の明らかなケースは、組み込みコマンドまたはキーワードです。which外部コマンドは、シェルに組み込まれているものが何であるかを知る方法がないためです(一部のシェルは組み込みの組み込みをzsh動的にロードできます)bashksh

$ type echo . time
echo is a shell builtin
. is a shell builtin
time is a shell keyword
$ which echo . time
/bin/echo
which: no . in (/bin:/usr/bin)
/usr/bin/time

zsh(これは内蔵された場所には適用されません)which

Solaris 10、AIX 7.1、HP/UX 11i、Tru64 5.1など:

$ csh
% which ls
ls:   aliased to ls -F
% unalias ls
% which ls
ls:   aliased to ls -F
% ksh
$ which ls
ls:   aliased to ls -F
$ type ls
ls is a tracked alias for /usr/bin/ls

これは、ほとんどの商用Unices which(3BSDの元の実装と同じ)からのcsh読み取りであるためです~/.cshrc。現在定義しているエイリアスと実際に使用しているシェルに関係なく、レポートするエイリアスはそこに定義されています。そうですね。

HP/UX または Tru64 の場合:

% echo 'setenv PATH /bin:/usr/bin' >> ~/.cshrc
% setenv PATH ~/bin:/bin:/usr/bin
% ln -s /bin/ls ~/bin/
% which ls
/bin/ls

$path(SolarisおよびAIXバージョンでは、読み込み前に保存~/.cshrcし、コマンドを見つける前に復元してこの問題を解決しました。)

$ type 'a b'
a b is /home/stephane/bin/a b
$ which 'a b'
no a in /usr/sbin /usr/bin
no b in /usr/sbin /usr/bin

または:

$ d="$HOME/my bin"
$ mkdir "$d"; PATH=$PATH:$d
$ ln -s /bin/ls "$d/myls"
$ type myls
myls is /home/stephane/my bin/myls
$ which myls
no myls in /usr/sbin /usr/bin /home/stephane/my bin

(もちろん、cshスクリプトとしてスペースを含む引数を処理すると期待することはできません...)

CentOS 6.4、バッシュ

$ type which
which is aliased to `alias | /usr/bin/which --tty-only --read-alias --show-dot --show-tilde'
$ alias foo=': "|test|"'
$ which foo
alias foo=': "|test|"'
        /usr/bin/test
$ alias $'foo=\nalias bar='
$ unalias bar
-bash: unalias: bar: not found
$ which bar
alias bar='

このシステムでは、GNUコマンドをラップするためにシステム全体にエイリアスが定義されていますwhich

偽の出力はsの出力を読みwhichましたが、正しく解析する方法がわからず、ヒューリスティック(1行に1つのエイリアス、、、...の後に最初に見つかったコマンドを見つける)を使用するためです。bashalias|;&

CentOSの最も悪いことは、zsh完全に良いwhich組み込みコマンドがありますが、CentOSはそれを機能しないGNUエイリアスに置き換えてそれを中断させることですwhich

Debian 7.0、ksh93:

(複数のシェルを持つほとんどのシステムに適用可能ですが)

$ unset PATH
$ which which
/usr/local/bin/which
$ type which
which is a tracked alias for /bin/which

Debianではスクリプト/bin/whichです/bin/sh。私が知る限りsh、それはそうですが、dashそんなときも同じですbash

設定を解除してもルックアップはPATH無効になりませんPATH。これはシステムのデフォルトパス残念ながら、Debianでは誰も同意しません(dashそしてbashhas /usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/binzshhas /bin:/usr/bin:/usr/ucb:/usr/local/binksh93has /bin:/usr/binmkshhas /usr/bin:/bin$(getconf PATH))、execvp()(like env)has :/bin:/usr/bin(はい、最初に現在のディレクトリを見てください))。

そのため、上記の場合とは異なるデフォルト値をwhich使用しているため、エラーが発生します。dashPATHksh93

GNUはより良いサービスを提供しておらず、which次のように報告します。

which: no which in ((null))

/usr/local/bin/whichakanga(興味深いことに、私のシステムには実際にスクリプトに付属するスクリプトがありますakangarcデフォルトはシェル派生ですPATH/usr/ucb:/usr/bin:/bin:.

bash、すべてのシステム:

唯一の人Chrisは彼の答えで言及しました。:

$ PATH=$HOME/bin:/bin
$ ls /dev/null
/dev/null
$ cp /bin/ls bin
$ type ls
ls is hashed (/bin/ls)
$ command -v ls
/bin/ls
$ which ls
/home/chazelas/bin/ls

また、hash手動で呼び出した後:

$ type -a which
which is /usr/local/bin/which
which is /usr/bin/which
which is /bin/which
$ hash -p /bin/which which
$ which which
/usr/local/bin/which
$ type which
which is hashed (/bin/which)

which今度は失敗する部分は次のとおりですtype

$ mkdir a b
$ echo '#!/bin/echo' > a/foo
$ echo '#!/' > b/foo
$ chmod +x a/foo b/foo
$ PATH=b:a:$PATH
$ which foo
b/foo
$ type foo
foo is b/foo

今、いくつかのシェルを使用してください。

$ foo
bash: ./b/foo: /: bad interpreter: Permission denied

他の人:

$ foo
a/foo

実行できないという事実を事前に知ることもできませwhichtypeb/foo一部のシェル(たとえば、bashまたはksh)は、呼び出されたときyashfoo実際に実行しようb/fooとし、エラーを報告しますが、他のシェル(たとえばzsh、、、、、、、、など)は、システムコールが失敗した場合に実行されます。ashcshBournetcsha/fooexecve()b/foo

答え3

Stephaneが言及していないことの1つは、(私のクイックビューでは)whichシェルのパスハッシュテーブルを知らないことです。その結果、実際の実行結果を示さない結果が返され、デバッグに役に立たなくなります。

答え4

(この質問には「移植性」というタグが付いているため、「対話型の使用」や「使用しているシステムにのみ興味があります」など、質問に対するさまざまな解釈は除外されます。シェルスクリプトでこれを行うべきではないのはなぜですか?)

Stéphaneはオプションの徹底的な分析を提供し、それぞれのオプションが良いか悪いかについての理由を提示します。どんな理由もwhich常に間違った答えではありません。代わりに小さな影響を与える要因がたくさんあります。そのうちの1つまたはいくつかに耐えることができますが、一緒に服用すると心が変わることがあります。

まだ言及されていないものを使用していない理由の1つは、次whichのような質問があるからです。

whichそもそもなぜ出力が欲しいのですか?

私が意味するのは、時々目標はドロップされた代替品を見つけるのではなく、which最初に必要とされない方法でコードをリファクタリングすることです。

一般的なパターンは次のとおりです。

CMD=$( which cmd )

# some time later...
$CMD --some --args

ほとんどいつも引用されていないという事実を控えて、$CMD全体のパターンが壊れたと思います。

CMD=/my/path/to/cmd依存関係を避けることが目的の場合は、ハードコーディングが重要です$PATH

しかし、とにかく検索すると、$PATHほとんど常に意味がありません。whichとを完全に削除し、$CMD以下を作成します。

cmd --some --args

関数やエイリアスにパスを含めるためにパスが必要だと思われる場合は、そのcommandパスを使用してください。

function cmd {
    command cmd --extra-arg "$@"
}

もちろん例外もあり、他に基づいている必要がありますPATH。この場合は、次のものを使用することをお勧めします。

function cmd {
    PATH=$OTHERPATH command cmd "$@"
}

全体的には、避ける「コマンドパスの入手方法」の精神的な近道がありますが、ケースバイケースで考えてみてください。この道は本当に必要ですか?なぜ?

場合によってはwhich許可されるかもしれませんが、少なくともある程度はより良い解決策があります。他の人のためのチュートリアルを書いている場合は、他のオプションについてもっと考えてみてください。


合理的だと思ってもCMD=$( which cmd ) ; ... $CMD args避けるべき他の理由があります。which

これは普遍的ではありません

これPOSIXに必要なコマンドのリストを含むcommandtype含まれていませんwhich

出力形式が指定されていません。

which義務があれば見せる説明なしでそのままコマンドを提供するのではなく、コマンドパスを指定してください。ほとんどのバージョンですが。

which foo以下を出力するのは完全に正当です。

  • foo might be /opt/foobar/bin/foo (unverified);または
  • foo is in /bin;または
  • ~foo/bin/foo~foofooのホームディレクトリを表す)または
  • /proc/1234/root/bin/foo(プロセス1234終了)

答えは最新ではないかもしれません。

(これは基本的にすべての形式を除外しますが、これにCMD=$( something ) ; ... $CMD ...限定されませんwhich。)

特定のコマンド名に対する実行可能ファイルの場所は、さまざまな理由で変更される可能性があります。

時々、あなたは以前の場所を望むかもしれませんし、そうでないかもしれません。

コマンドへのパスが相対的な場合もあります(したがって.開始ではありません/)。これは通常セキュリティ上のリスクと見なされるため、まれですが、単に実行すると、cdプログラムパスが無効になる可能性がある特別な場合にも当てはまります。

関連情報