実行可能ファイルへのパスを見つけたり、Unixシェルにコマンド名を入力したりすると、何が起こるのかを判断するためのさまざまなユーティリティ(、、、、、など)がwhich
あります。type
command
whence
where
whereis
whatis
hash
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
)。csh
csh
解放、1979年2BSD
5月).cshrc
カスタムシェルに対しても処理されます(たとえば、各シェルはcsh
スクリプト.cshrc
のようにインタラクティブでない場合も読み取られます)。
rc
Bourneシェルは1979年初頭にUnix V7で初めてリリースされましたが、機能サポートははるかに後で追加されました(1984年SVR2で)、いずれの場合もいくつかのファイルがありませんでした(.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のBourneシェルに同様の機能が追加されましたtype
。 (外部スクリプトではなく)組み込まれているという事実はできるシェルの内部にアクセスできるので、正しい情報(ある程度)を提供します。
初期コマンドは、コマンドが見つからない場合に失敗した終了状態を返さないという点で、type
スクリプトと同様の問題を経験しました。また、実行ファイルの場合は、代わりに同様のものを出力するのwhich
とは異なり、スクリプトで使用するのは簡単ではありません。which
ls is /bin/ls
/bin/ls
Unixバージョン8(一般には公開されていません)のBourneシェルに組み込まれている関数のtype
名前が変更され、whatis
引数と印刷関数の定義も報告するように拡張されました。また、type
名前が見つからないときに失敗が返されない問題を解決します。
rc
、Plan9(ワンタイムUnix以降)シェル(およびakanga
などの派生製品es
)whatis
も使用できます。
sh
80年代半ばに開発されたが、1988年以前には広く使用されていなかったKornシェル(POSIX定義の基礎となるサブセット)csh
は、Bourneシェルの上に多くの機能(ラインエディタ、エイリアス...)を追加しました。これには、いくつかのオプション(同様に詳細な出力を提供し、実行可能ファイルのみを検索(別名/関数の代わりに...))を使用する独自の組み込みwhence
関数()が追加されます。type
-v
type
-p
AT&TとBerkeleyとの著作権紛争と同時に一部フリーソフトウェアシェルの実装は1980年代後半と1990年代初頭に登場しました。 Almquistシェル(BSDのBourneシェルに代わるもの)ash
(FSFスポンサー)のすべてのパブリックドメインの実装は、1989年から1991年の間に登場しました。ksh
pdksh
bash
zsh
AshはBourneシェルを置き換えることを意図していましたが、type
ずっと後で(NetBSD 1.3とFreeBSD 2.3で)組み込み機能はありませんでしたhash -v
。ただし、OSF / 1にはOSFまで常に0を返す組み込み機能が/bin/sh
ありました。type
/ 1 v3.x。bash
何も追加されていませんが、パス( like )とレポートを印刷するオプションがwhence
追加されました。-p
type
type -p
whence -p
-a
みんな一致するコマンド。 s -likeコマンドがtcsh
組み込まれてwhich
追加されました。すべて。where
bash
type -a
zsh
Shell fish
(2005)では、コマンドがtype
関数として実装されています。
同時に、cshスクリプトはwhich
NetBSDから削除され(tcshに組み込まれていて他のシェルではあまり使用されていないため)、機能が追加されました(呼び出されたwhereis
とき)。 OpenBSDとFreeBSDではこれもCで書かれています。which
whereis
which
$PATH
which
$PATH
実装する
さまざまな Unices には、コマンドの数十種類の構文とwhich
動作の実装があります。
tcsh
Linuxでは、(およびの組み込み実装に加えて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
zsh
、zsh/parameters
コマンドハッシュテーブルは、モジュールのcommands
連想配列としても使用されます。
$ print -r -- $commands[ls]
/bin/ls
このユーティリティ(Unix V8 BourneシェルまたはPlan 9 /のユーティリティをwhatis
除く)は、ドキュメント(greps Whatisデータベース、つまりマニュアルページの概要)にのみ使用されるため、実際には関係ありません。rc
es
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
Bourneのようなすべてのシェルに共通です。 (@jarnoが指摘したように、以下の説明の「POSIXモードではないとき」またはAlmquistの一部の子孫のcommand -v
警告/エラーに注意してください。シェル)。使用したい唯一のシェルです(そこにはシェルがなく、組み込まれているからです)。bash
tcsh
which
type
which
tcsh
シェルの外側のシェルでは、シェルzsh
起動which
ファイルの1つまたは一部に同じ名前のエイリアスまたは関数がなく、それに対して定義されたエイリアスまたは関数がない限り、~/.cshrc
これは~/.bashrc
ユーザーに通知することも、そうでない場合もあります。間違ったことを教えてください。$PATH
~/.cshrc
特定の名前のすべてのコマンドを知りたい場合は、移植可能なものはありません。where
intcsh
または inzsh
または in ksh93 およびその他のシェルを使用でき、それらを組み合わせることができます。type -a
bash
zsh
whence -a
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
返されることがあります。場合によっては、これを考慮する必要があります。組み込み関数のリストは、シェルの実装(時にはbusyboxの組み込み関数)によって異なります。たとえば、環境で関数を取得できることを覚えておいてください。foo
$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
存在しないものを返しますします。
コマンドが存在することを確認する
特定のコマンドが標準として存在することを確認するには、次のようにします。
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
他のシェルでは、以下を好みます。
- 扱いにくい:
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
のオペレーティングシステムでは使用できます(オペレーティングシステムごとにオプションと動作が異なります)。command
which
外部コマンドが必要な状況は、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
このトリックを使用する必要はありません。