実行可能ファイルへのパスを探したり、Unixシェルにコマンド名を入力した場合に何が起こるかを確認したりする場合、さまざまなユーティリティ(which
)が多数あります。 、type
、command
、whence
、where
、whereis
、whatis
、hash
など)。
そのwhich
をよく耳にします 避けるべきです。なんで?代わりに何を使うべきですか?
承認された回答:
これが、あなたがそれについて知りたくないと思ったことのないすべてです:
概要
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
インタラクティブなボーンのようなシェルのプロンプトで:
type ls
which
コマンドはCシェルからの壊れた遺産であり、ボーンのようなシェルにそのままにしておく方がよいでしょう。
ユースケース
スクリプトの一部としてその情報を検索することと、シェルプロンプトでインタラクティブに検索することには違いがあります。
シェルプロンプトでの一般的な使用例は次のとおりです。このコマンドは奇妙な動作をします。正しいコマンドを使用していますか? mycmd
と入力したときに正確に何が起こったのか ?それが何であるかをさらに調べることはできますか?
その場合、実際にコマンドを呼び出さずにコマンドを呼び出したときにシェルが何をするかを知りたいと思います。
シェルスクリプトでは、かなり異なる傾向があります。シェルスクリプトでは、実行するだけでコマンドがどこにあるのか、何であるのかを知りたい理由はありません。一般に、知りたいのは実行可能ファイルのパスであるため、実行可能ファイルからより多くの情報を取得できます(それに関連する別のファイルへのパスや、そのパスにある実行可能ファイルのコンテンツから情報を読み取るなど)。
インタラクティブに、すべてについて知りたい場合があります my-cmd
システム上で、スクリプトで使用できるコマンドは、めったにありません。
利用可能なツールのほとんど(よくあることですが)は、インタラクティブに使用できるように設計されています。
歴史
最初に少し歴史があります。
70年代後半までの初期のUnixシェルには、関数やエイリアスがありませんでした。 $PATH
での実行可能ファイルの従来の検索のみ 。 csh
1978年頃にエイリアスが導入されました(ただし、csh
最初にリリースされた 2BSD
で 、1979年5月)、および.cshrc
の処理 ユーザーがシェルをカスタマイズできるようにします(すべてのシェル、csh
、.cshrc
を読み取ります スクリプトのようにインタラクティブでない場合でも)
Bourneシェルは1979年の初めにUnixV7で最初にリリースされましたが、関数のサポートはずっと後に追加され(SVR2では1984)、とにかく、rc
はありませんでした。 ファイル(.profile
シェル自体ではなく、環境を構成することです 。
csh
Bourneシェルよりもはるかに人気がありました(Bourneシェルよりも構文が非常に悪いものでしたが)、インタラクティブに使用するためのより便利で優れた機能が多数追加されていました。
3BSD
で (1980)、which
csh
にcshスクリプトが追加されました 実行可能ファイルの識別を支援するユーザー。これは、which
として見つけることができるほとんど異なるスクリプトです。 最近の多くの商用Unices(Solaris、HP / UX、AIX、Tru64など)で。
そのスクリプトは、ユーザーの~/.cshrc
を読み取ります (すべてのcsh
のように csh -f
で呼び出されない限り、スクリプトは実行されます )、エイリアスのリストと$path
で指定されたコマンド名を検索します (csh
の配列 $PATH
に基づいて維持 。
ここに行きます:which
当時最も人気のあったシェル(およびcsh
)が最初に登場しました 90年代半ばまでまだ人気がありました)。これが、本に記録され、今でも広く使用されている主な理由です。
csh
の場合でも注意してください ユーザー、そのwhich
cshスクリプトは、必ずしも正しい情報を提供するとは限りません。 ~/.cshrc
で定義されたエイリアスを取得します 、後でプロンプトで、またはたとえばsource
によって定義したものではありません 別のcsh
を作成する ファイル、および(それは良い考えではありませんが)、PATH
~/.cshrc
で再定義される可能性があります 。
そのwhich
を実行する Bourneシェルからのコマンドは、~/.cshrc
で定義されたエイリアスを引き続き検索します 、ただし、csh
を使用していないために持っていない場合 、それでもおそらく正しい答えが得られるでしょう。
同様の機能は、1984年までSVR2でtype
を使用してBourneシェルに追加されませんでした。 組み込みコマンド。 (外部スクリプトではなく)組み込みであるという事実は、できることを意味します。 シェルの内部にアクセスできるため、適切な情報を(ある程度)提供します。
最初のtype
コマンドはwhich
と同様の問題を抱えていました コマンドが見つからなかった場合に失敗の終了ステータスを返さなかったという点でスクリプト。また、実行可能ファイルの場合、which
とは異なります 、ls is /bin/ls
のようなものを出力します /bin/ls
の代わりに これにより、スクリプトでの使用が難しくなりました。
Unixバージョン8(実際にはリリースされていません)のBourneシェルにはtype
がありました ビルトインの名前がwhatis
に変更されました また、パラメータと印刷関数の定義についてもレポートするように拡張されました。 type
も修正されました 名前が見つからない場合に失敗を返さないという問題。
rc
、Plan9(Unixのかつての後継となる)のシェル(およびakanga
のようなその派生物 およびes
)whatis
があります 同様に。
Kornシェル(そのサブセットはPOSIX sh
定義は)に基づいており、80年代半ばに開発されましたが、1988年以前には広く利用可能ではなく、csh
の多くが追加されました。 Bourneシェルの上部にある機能(ラインエディタ、エイリアス…)。独自のwhence
を追加しました 組み込み(type
に加えて )いくつかのオプションを取りました(-v
type
を提供する -冗長な出力のように、-p
実行可能ファイルのみを検索します(エイリアス/関数は検索しません…))。
AT&TとBerkeleyの間の著作権問題に関する混乱と同時期に、いくつかの無料ソフトウェア シェルの実装は、80年代後半から90年代前半に発表されました。すべてのAlmquistシェル(ash
、BSDのBourneシェルの代わりになります)、ksh
のパブリックドメイン実装 (pdksh
)、bash
(FSFが後援)、zsh
1989年から1991年の間に発表されました。
Ashは、Bourneシェルの代わりになることを目的としていましたが、type
を持っていませんでした。 hash -v
がありましたが、ずっと後まで(NetBSD1.3およびFreeBSD2.3で)組み込まれていました。 。 OSF / 1 /bin/sh
type
がありました OSF /1v3.xまでは常に0を返すビルトイン。 bash
whence
を追加しませんでした ただし、-p
を追加しました type
のオプション パスを出力するには(type -p
whence -p
のようになります )および-a
すべてを報告する 一致するコマンド。 tcsh
which
を作成しました 組み込みで、where
を追加しました bash
のように機能するコマンド のtype -a
。 zsh
それらすべてを持っています。
fish
shell(2005)にはtype
があります 関数として実装されたコマンド。
which
一方、cshスクリプトはNetBSDから削除され(tcshに組み込まれていて、他のシェルではあまり使用されていないため)、機能がwhereis
に追加されました。 (which
として呼び出された場合 、whereis
which
のように動作します ただし、$PATH
で実行可能ファイルのみを検索します。 )。 OpenBSDおよびFreeBSDでは、which
また、$PATH
でコマンドを検索するCで記述されたものに変更されました。 のみ。
実装
which
の実装は数十あります 構文と動作が異なるさまざまなユニスに対するコマンド。
Linuxの場合(tcsh
に組み込まれているもののほかに およびzsh
)いくつかの実装があります。たとえば、最近のDebianシステムでは、$PATH
でコマンドを検索する単純なPOSIXシェルスクリプトです。 。
busybox
which
もあります コマンド。
GNU
があります which
これはおそらく最も贅沢なものです。 which
を拡張しようとします cshスクリプトは他のシェルに対して行いました:より良い答えを与えることができるように、エイリアスと関数が何であるかを伝えることができます(そして、一部のLinuxディストリビューションはbash
の周りにいくつかのグローバルエイリアスを設定すると思います
zsh
オペレーターが2人います 実行可能ファイルのパスに展開するには:=
ファイル名の拡張 演算子と:c
履歴拡張修飾子(ここではパラメータ拡張に適用されます ):
$ print -r -- =ls
/bin/ls
$ cmd=ls; print -r -- $cmd:c
/bin/ls
zsh
、zsh/parameters
モジュールはまた、コマンドハッシュテーブルをcommand
として作成します 連想配列:
$ print -r -- $commands[ls]
/bin/ls
whatis
ユーティリティ(UnixV8BourneシェルまたはPlan9rc
のものを除く / es
)はドキュメント専用であるため、実際には関連していません(whatisデータベース、つまりマニュアルページの概要を把握しています)。
whereis
3BSD
にも追加されました which
と同時に C
で書かれていますが 、csh
ではありません また、実行可能ファイル、マニュアルページ、およびソースを同時に検索するために使用されますが、現在の環境に基づくものではありません。繰り返しになりますが、それは別のニーズに答えます。
現在、標準の面では、POSIXはcommand -v
を指定しています および-V
コマンド(POSIX.2008まではオプションでした)。 UNIXはtype
を指定します コマンド(オプションなし)。以上です(where
、which
、whence
どの規格にも指定されていません。
いくつかのバージョンまで、type
およびcommand -v
Linux Standard Base仕様ではオプションでした。これは、たとえば、いくつかの古いバージョンのposh
が理由を説明しています。 (ただし、pdksh
に基づいています 両方を持っていた)どちらも持っていなかった。 command -v
一部のBourneシェル実装(Solarisなど)にも追加されました。
今日のステータス
最近の状況は、そのtype
およびcommand -v
ボーンのようなすべてのシェルに遍在しています(ただし、@ jarnoで指摘されているように、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
の場合/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
を返す場合もあります$PATH
の場合 空の文字列が含まれ、実行可能なfoo
があります 現在のディレクトリ内のファイル。それを考慮に入れる必要があるかもしれないいくつかの状況があります。たとえば、ビルトインのリストはシェルの実装によって異なることに注意してください(たとえば、mount
時々busyboxsh
に組み込まれています )、たとえばbash
環境から関数を取得できます。 -
$PATH
の場合 相対パスコンポーネント(通常は.
)が含まれます または、両方とも現在のディレクトリを参照しているが、何でもかまいません)、シェルに応じて、command -v cmd
絶対パスを出力しない場合があります。したがって、command -v
を実行したときに取得するパスcd
を実行すると、無効になります どこか別の場所。 - 逸話:
/opt/ast/bin
の場合、ksh93シェルを使用 (正確なパスはシステムによって異なる可能性がありますが)$PATH
にあります 、ksh93は、いくつかの追加のビルトイン(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
を使用することが理にかなっている場合 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 、アカンガ :
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
を使用する 、そのトリックを使用する必要はありません。