以下は、あなたがそれについて知りたくないと思ったことのないすべてです。
概要
Bourneのようなシェルスクリプトで実行可能ファイルのパス名を取得するには(いくつか注意点があります。以下を参照してください):
ls=$(command -v ls)
特定のコマンドが存在するかどうかを確認するには:
if command -v given-command > /dev/null 2>&1; then
echo given-command is available
else
echo given-command is not available
fi
インタラクティブなBourneのようなシェルのプロンプトで:
type ls
このwhichコマンドはCシェルの壊れた遺産であり、Bourneのようなシェルにはそのままにしておく方が良いでしょう。
ユースケース
スクリプトの一部として、またはシェルプロンプトで対話的に情報を検索することには違いがあります。
シェルプロンプトでの一般的な使用例は次のとおりです。このコマンドの動作がおかしいのですが、正しいコマンドを使用していますか?入力したときに正確に何が起こったのmycmdですか?それが何であるかをさらに調べることはできますか?
その場合、実際にコマンドを呼び出さずにコマンドを呼び出したときにシェルが何をするかを知りたいと思うでしょう。
シェルスクリプトでは、まったく異なる傾向があります。シェルスクリプトでは、実行したいだけでコマンドがどこにあるか、または何であるかを知りたい理由はありません。一般に、知りたいのは実行可能ファイルのパスです。そのため、より多くの情報を取得できます(そのファイルに関連する別のファイルへのパス、またはそのパスにある実行可能ファイルのコンテンツから情報を読み取る)。
対話的に、システムで使用可能なすべてのmy-cmdコマンドをスクリプトで知りたい場合があります。
利用可能なツールのほとんどは(多くの場合そうであるように)インタラクティブに使用されるように設計されています。
歴史
最初に少し歴史。
70年代後半までの初期のUnixシェルには、関数やエイリアスがありませんでした。従来の実行可能ファイルの検索のみ$PATH。csh1978年頃にエイリアスを導入しました(ただし、1979年5月cshにで最初にリリースされました2BSD)。また、.cshrcユーザーがシェルをカスタマイズするための処理(すべてのシェル、スクリプトのようにインタラクティブではない場合でもcsh読み取り.cshrc)。
Bourneシェルは1979年の早い時期にUnix V7で最初にリリースされましたが、関数サポートはかなり後で追加され(SVR2では1984年)、とにかく、rcファイルがありません(.profileシェル自体ではなく環境を構成するためです)。
csh (Bourneシェルよりもひどく悪い構文でしたが)Bourneシェルよりもはるかに人気があり、インタラクティブに使用するためのより便利で素晴らしい機能がたくさん追加されました。
で3BSD(1980)、whichCSHスクリプトが追加されましたcsh実行可能ファイルを識別しやすくするために、ユーザー、そしてそれはあなたのように見つけることができるほとんど変わらないスクリプトですwhich、今日は(Solaris、HP / UX、AIXまたはのTru64など)多くの商用のUnix上。
そのスクリプトはユーザーの~/.cshrc(すべてのcshスクリプトがで呼び出されない限り行うように)を読み取り、csh -fエイリアスのリストと$path(にcsh基づいて維持する配列)で提供されたコマンド名を検索し$PATHます。
ここwhichで、最も人気のあるシェルで最初に登場しました(そしてcsh90年代半ばまでまだ人気がありました)。これが本で文書化され、今でも広く使用されている主な理由です。
cshユーザーであっても、そのwhichcshスクリプトは必ずしも正しい情報を提供するとは限らないことに注意してください。それはで定義されたエイリアスを取得します。~/.cshrcプロンプトで、またはsource別のcshファイルを使用して後で定義したエイリアスではなく、(それは良い考えでPATHはありませんが)で再定義され~/.cshrcます。
whichBourneシェルからそのコマンドを実行すると、で定義されたエイリアスを引き続き検索しますが~/.cshrc、を使用していないためエイリアスがない場合はcsh、おそらく正しい答えが得られます。
type組み込みコマンドを使用したSVR2の1984年まで、同様の機能はBourneシェルに追加されませんでした。(外部スクリプトとは対照的に)組み込みであるという事実は、シェルの内部にアクセスできるため、(ある程度)適切な情報を提供できることを意味します。
最初のtypeコマンドにはwhich、コマンドが見つからない場合に失敗終了ステータスを返さないという点で、スクリプトと同様の問題がありました。また、実行可能ファイルの場合、とは反対にwhich、スクリプトでの使用が簡単になったls is /bin/lsだけ/bin/lsではなく、次のようなものを出力します。
Unixバージョン8(type非公開)Bourneシェルでは、組み込みの名前がに変更されましたwhatis。そして、Plan9の(のUnix一度に-こと後継)シェルrc(などその誘導体akangaとはes)持っているwhatisとしても。
80年代半ばに開発されたが1988年以前に広く利用できなかったKornシェル(POSIX sh定義のベースとなっているサブセットcsh)は、Bourneシェルの上に多くの機能(ラインエディター、エイリアス...)を追加しました。whence(-に加えてtype)独自の組み込みを追加し、いくつかのオプションを取りました(-likeのような詳細な出力-vを提供し、実行可能ファイル(エイリアス/関数ではなく...)のみを検索します)。type-p
AT&TとBerkeleyの間の著作権の問題に関する混乱と同時期に、80年代後半から90年代初頭にいくつかのフリーソフトウェアシェルの実装が登場しました。すべてのAlmquistシェル(BSD、Bourneシェルの代替)、ksh(pdksh)のパブリックドメイン実装(bashFSFがスポンサー)は、zsh1989年から1991年の間に登場しました。
Ashは、Bourneシェルの代わりになることを意図していましたが、typeずっと後(NetBSD 1.3およびFreeBSD 2.3)になるまで組み込まれていませんでしたhash -v。OSF / 1に/bin/shは、typeOSF / 1 v3.xまで常に0を返すビルトインがありました。bashは追加しませんでしたwhenceが、パスを印刷する-pオプションtype(のtype -pようになりますwhence -p)および一致するすべてのコマンド-aを報告するオプションを追加しました。作られた組み込み、コメントを追加しましたような演技コマンドのを。それらがすべてあります。tcshwhichwherebashtype -azsh
fishシェル(2005)はtype関数として実装コマンド。
which一方、cshスクリプトはNetBSDから削除され(tcshに組み込まれており、他のシェルではあまり使用されないため)、追加された機能whereis(として呼び出されるとwhich、でのみ実行可能ファイルを検索すること以外whereisは同様に動作whichします$PATH)。OpenBSDおよびFreeBSDでも、whichコマンド$PATHのみを検索するCで記述されたものに変更されました。
実装
whichさまざまな構文と動作を備えたさまざまなUnicesには、コマンドの実装が多数あります。
Linuxでは(とに組み込まれているもののほかtcshにzsh)いくつかの実装があります。たとえば、最近のDebianシステムでは、のコマンドを探す単純なPOSIXシェルスクリプトです$PATH。
busyboxwhichコマンドもあります。
ありGNU which、おそらく最も贅沢な1です。それはどのような拡張しようとするwhichのcshスクリプトが他のシェルにした:あなたはそれがあなたのより良い答えを与えることができます(と私はいくつかのLinuxディストリビューションは、のためにその周りにいくつかのグローバルエイリアスを設定すると考えているように、あなたのエイリアスや関数が何であるか、それを伝えることができるbashことを行います) 。
zshには、実行可能ファイルのパスに展開する2つの演算子があります。= ファイル名展開演算子と:c履歴展開修飾子(ここではパラメーター展開に適用されます):
$ print -r -- =ls
/bin/ls
$ cmd=ls; print -r -- $cmd:c
/bin/ls
zsh、zsh/parametersモジュールでは、commands連想配列としてコマンドハッシュテーブルも作成します。
$ print -r -- $commands[ls]
/bin/ls
whatis(UnixのV8 Bourneシェルまたはプラン9の1を除き、ユーティリティrc/がes)実際にそれが唯一のドキュメンテーションのためだとは関係ありません(whatisデータベースをgrepする、それはmanページの概要です)。
whereisまた、現在の環境に基づいていないが、実行可能ファイル、マニュアルページ、およびソースを同時に検索するために使用され、同時に検索されないように記述され3BSDてwhichいるように、同時に追加されました。繰り返しますが、それは別のニーズに答えます。Ccsh
現在、標準的な面では、POSIXはcommand -vand -Vコマンド(POSIX.2008まではオプションでした)を指定します。UNIXはtypeコマンドを指定します(オプションなし)。それはすべてです(where、which、whence任意の標準で規定されていません)
あるバージョンまででtypeありcommand -v、Linux Standard Base仕様ではオプションでした。これにより、たとえばposh(旧バージョンと旧バージョンのpdksh両方の)一部の旧バージョンがどちらもなかった理由が説明されます。command -vいくつかのBourneシェル実装(Solarisなど)にも追加されました。
今日のステータス
最近は状況がそれであるtypeとcommand -v(で警告/バグに注意し、@jarnoで述べたように、しかし、すべてのBourneのようなシェルに遍在しているbashPOSIXモードまたはAlmquistのいくつかの子孫でコメントで以下のシェルでないときに)。tcsh使用したい唯一のシェルですwhich(ないtypeのでwhich組み込みです)。
以外のシェルにtcshとzsh、which限りそこにはエイリアスや関数が同じ名前によって私達のいずれかでませんよう、あなたに与えられた実行ファイルのパスを伝えること~/.cshrc、~/.bashrcまたは任意のシェル起動ファイルは、あなたが定義していない$PATHあなたに~/.cshrc。エイリアスまたは関数が定義されている場合、それについて通知されたり、されなかったり、間違ったことを伝えたりする場合があります。
特定の名前のすべてのコマンドについて知りたい場合、移植性のあるものはありません。あなたは使うだろうwhereにtcshかzsh、type -a中bashかzsh、whence -aは、ksh93にし、他のシェルでは、使用することができますtypeとの組み合わせでwhich -a動作する可能性があります。
推奨事項
実行可能ファイルへのパス名を取得する
ここで、スクリプトで実行可能ファイルのパス名を取得するには、いくつかの注意事項があります。
ls=$(command -v ls)
それを行う標準的な方法でしょう。
ただし、いくつかの問題があります。
- 実行せずに実行可能ファイルのパスを知ることはできません。すべての
type、which、command -v...すべてのパスを見つけるために、ヒューリスティックを使用しています。$PATHコンポーネントをループし、実行権限を持つ最初の非ディレクトリファイルを見つけます。ただし、シェルによっては、コマンドの実行に関しては、それらの多く(Bourne、AT&T ksh、zsh、ash ...)は$PATH、execveシステムコールがエラーを返さないまでの順序で実行されます。 。たとえば、$PATHcontains /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も返さfooれることがあります。それを考慮する必要がある状況がいくつかあります。たとえば、組み込みのリストはシェルの実装によって異なり(たとえば、busyboxの組み込みである場合があります)、たとえば環境から関数を取得できることに注意してください。$PATHfoomountshbash
$PATH相対パスコンポーネント(通常、.または両方とも現在のディレクトリを参照しますが、任意の空の文字列)が含まれている場合、シェルによってはcommand -v cmd、絶対パスが出力されない場合があります。そのため、実行時に取得したパスは、どこか別の場所ではcommand -v無効になりcdます。
- 逸話:は、ksh93シェルで、あれば
/opt/ast/bin(つまり、正確なパスは、私は信じて異なるシステムで異なることができますが)があなたの中にある$PATH、は、ksh93は、いくつかの余分なビルトイン(利用できるようになりますchmod、cmp、cat...)が、command -v chmod返され/opt/ast/bin/chmod、そのパスが」doesnの場合でも、存在します。
コマンドが存在するかどうかの判断
特定のコマンドが標準的に存在するかどうかを確認するには、次のようにします。
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が理にかなっているケースは、コマンドのパスを知りたい場合、潜在的なシェル組み込み関数、またはbash、csh(ではないtcsh)、、dashまたはBourneシェルスクリプト、つまりwhence -p(kshまたはのようなzsh)シェルスクリプトを無視する場合です、command -ev(のようなyash)、whatis -p(rc、akanga)、またはスクリプトではない利用可能なシステムの組み込みwhich(tcshまたはのようなzsh)。whichcsh
これらの条件が満たされている場合、次のようになります。
echo=$(which echo)
あなたの最初のパス与えるecho中を$PATH(コーナーケースを除いて)に関係なく、かどうかのecho、シェルの組み込み/エイリアス/機能かどうかであることを起こります。
他のシェルでは、次をお勧めします。
- zshの:
echo==echoまたはecho=$commands[echo]またはecho=${${:-echo}:c}
- ksh、zsh:
echo=$(whence -p echo)
- ヤシュ:
echo=$(command -ev echo)
- rc、akanga:(
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コマンド(など)を外部コマンドとしても使用できるようにする必要がありますが、残念ながらcommand多くのシステムではそうではありません。たとえば、commandLinuxベースのオペレーティングシステムでコマンドを見つけることはほとんどありませんが、ほとんどのwhichコマンドにはコマンドがあります(ただし、オプションや動作が異なるものは異なります)。
外部コマンドが必要な場合は、POSIXシェルを呼び出さずにコマンドを実行する場所です。
system("some command line")、popen()... Cまたは様々な言語の機能は、そのコマンドラインを解析するためにシェルを起動し、そうsystem("command -v my-cmd")彼らに作業を行います。例外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、あなたはそのトリックを使用する必要はありません。
whichは、対話型のシェルコンテキストを想定していると思います。この質問には/ portabilityというタグが付けられています。したがって、このコンテキストの質問whichは、$PATH「特定の名前の最初の実行可能ファイルを見つけるのではなく、何を使用するか」と解釈します。ほとんどの答えと理由whichは、ほとんどの実世界のポータブルシェルスクリプトで学術的な関心事であるエイリアス、組み込み関数、および関数を処理します。ローカルで定義されたエイリアスは、シェルスクリプトの実行時に継承されません(ソースコードを使用してソースを作成する場合を除く.)。