以下は、あなたがそれについて知りたくないと思ったことのないすべてです。
概要
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
。csh
1978年頃にエイリアスを導入しました(ただし、1979年5月csh
にで最初にリリースされました2BSD
)。また、.cshrc
ユーザーがシェルをカスタマイズするための処理(すべてのシェル、スクリプトのようにインタラクティブではない場合でもcsh
読み取り.cshrc
)。
Bourneシェルは1979年の早い時期にUnix V7で最初にリリースされましたが、関数サポートはかなり後で追加され(SVR2では1984年)、とにかく、rc
ファイルがありません(.profile
シェル自体ではなく環境を構成するためです)。
csh
(Bourneシェルよりもひどく悪い構文でしたが)Bourneシェルよりもはるかに人気があり、インタラクティブに使用するためのより便利で素晴らしい機能がたくさん追加されました。
で3BSD
(1980)、which
CSHスクリプトが追加されましたcsh
実行可能ファイルを識別しやすくするために、ユーザー、そしてそれはあなたのように見つけることができるほとんど変わらないスクリプトですwhich
、今日は(Solaris、HP / UX、AIXまたはのTru64など)多くの商用のUnix上。
そのスクリプトはユーザーの~/.cshrc
(すべてのcsh
スクリプトがで呼び出されない限り行うように)を読み取り、csh -f
エイリアスのリストと$path
(にcsh
基づいて維持する配列)で提供されたコマンド名を検索し$PATH
ます。
ここwhich
で、最も人気のあるシェルで最初に登場しました(そしてcsh
90年代半ばまでまだ人気がありました)。これが本で文書化され、今でも広く使用されている主な理由です。
csh
ユーザーであっても、そのwhich
cshスクリプトは必ずしも正しい情報を提供するとは限らないことに注意してください。それはで定義されたエイリアスを取得します。~/.cshrc
プロンプトで、またはsource
別のcsh
ファイルを使用して後で定義したエイリアスではなく、(それは良い考えでPATH
はありませんが)で再定義され~/.cshrc
ます。
which
Bourneシェルからそのコマンドを実行すると、で定義されたエイリアスを引き続き検索しますが~/.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)のパブリックドメイン実装(bash
FSFがスポンサー)は、zsh
1989年から1991年の間に登場しました。
Ashは、Bourneシェルの代わりになることを意図していましたが、type
ずっと後(NetBSD 1.3およびFreeBSD 2.3)になるまで組み込まれていませんでしたhash -v
。OSF / 1に/bin/sh
は、type
OSF / 1 v3.xまで常に0を返すビルトインがありました。bash
は追加しませんでしたwhence
が、パスを印刷する-p
オプションtype
(のtype -p
ようになりますwhence -p
)および一致するすべてのコマンド-a
を報告するオプションを追加しました。作られた組み込み、コメントを追加しましたような演技コマンドのを。それらがすべてあります。tcsh
which
where
bash
type -a
zsh
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
。
busybox
which
コマンドもあります。
あり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
いるように、同時に追加されました。繰り返しますが、それは別のニーズに答えます。C
csh
現在、標準的な面では、POSIXはcommand -v
and -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のようなシェルに遍在しているbash
POSIXモードまたは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
システムコールがエラーを返さないまでの順序で実行されます。 。たとえば、$PATH
contains /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の組み込みである場合があります)、たとえば環境から関数を取得できることに注意してください。$PATH
foo
mount
sh
bash
$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
)。which
csh
これらの条件が満たされている場合、次のようになります。
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
多くのシステムではそうではありません。たとえば、command
Linuxベースのオペレーティングシステムでコマンドを見つけることはほとんどありませんが、ほとんどの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
は、ほとんどの実世界のポータブルシェルスクリプトで学術的な関心事であるエイリアス、組み込み関数、および関数を処理します。ローカルで定義されたエイリアスは、シェルスクリプトの実行時に継承されません(ソースコードを使用してソースを作成する場合を除く.
)。