実行可能ファイルへのパスを検索するとき、または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コマンドについてスクリプトで知りたい場合があります。 p>
利用可能なツールのほとんど(よくあることですが)は、インタラクティブに使用できるように設計されています。
履歴
最初に少し履歴を付けます。
70年代後半までの初期のUnixシェルには、関数やエイリアスがありませんでした。 $PATHでの実行可能ファイルの従来の検索のみ。 cshは1978年頃にエイリアスを導入しました(ただし、cshは2BSDで最初にリリースされました / div>、1979年5月)、およびユーザーがシェルをカスタマイズするための.cshrcの処理(すべてのシェル、csh 、スクリプトのようにインタラクティブでない場合でも.cshrcを読み取ります。
Bourneシェルは1979年の初めにUnixV7で最初にリリースされましたが、関数のサポートは大幅に追加されました。後で(SVR2では1984年)、とにかく、rcファイルはありませんでした(.profileは、シェルではなく環境を構成するためのものですそれ自体)。
cshは、Bourneシェルよりもはるかに人気がありました(ただし、構文はBourneシェルよりもひどく劣っていました) Bourne shell)インタラクティブに使用するためのより便利で優れた機能がたくさん追加されていました。
3BSD(1980)では、 which cshスクリプトがcshユーザー向けに追加され、実行可能ファイルを識別できるようになりました。これは、最近の多くの商用Unice(Solaris、HP / UX、AIX、Tru64など)。
そのスクリプトはユーザーの~/.cshrc (すべてのcshスクリプトは、csh -fで呼び出されない限り実行されます)、エイリアスのリストで指定されたコマンド名を検索し、 $path(cshが$PATHに基づいて維持する配列)
ここに行きます:whichは、当時最も人気のあったシェルで最初に登場しました(そして、cshは、半ばまでまだ人気がありました- 90年代)、これが本に記載され、今でも広く使用されている主な理由です。
cshユーザーの場合でも、which cshスクリプトは必ずしもあなたに与えるとは限りません正しい情報。 ~/.cshrcで定義されたエイリアスを取得します。後でプロンプトで定義したエイリアスや、たとえばsource別の
ファイル、および(それは良い考えではありませんが)、PATHは~/.cshrc。
Bourneシェルからwhichコマンドを実行すると、~/.cshrcで定義されているエイリアスが検索されますが、 cshを使用していないために持っていない場合でも、おそらく正しい答えが得られます。
同様の機能はに追加されていません。 type組み込みコマンドを使用したSVR2の1984年までのBourneシェル。 (外部スクリプトではなく)組み込みであるという事実は、シェルの内部にアクセスできるため、 適切な情報を(ある程度)提供できることを意味します。
最初のtypeコマンドには、whichスクリプトと同様の問題があり、次の場合に失敗の終了ステータスが返されませんでした。コマンドが見つかりませんでした。また、実行可能ファイルの場合、whichとは異なり、iv id = “ではなくls is /bin/lsのように出力されます。 1ef2ca896a “>
により、スクリプトでの使用が容易になりませんでした。
Unixバージョン8″(実際にはリリースされていません)Bourneシェルにはtypeビルトインの名前がwhatisに変更されました。Plan9(かつてはUnixの後継であった)シェルrc(およびそのakangaやes)などの派生物にもwhatisがあります。
Kornシェル(そのサブセットのPOSIX shの定義は)に基づいており、80年代半ばに開発されましたが、1988年以前は広く利用できませんでしたが、csh機能の多くが追加されました( Bourneシェルの上にあるラインエディタ、エイリアス…)。独自のwhenceビルトイン(typeに加えて)を追加し、いくつかのオプションを取りました(-v typeのような詳細な出力を提供し、-pは実行可能ファイルのみを検索します(エイリアス/関数ではありません…)) 。
AT & Tとバークレーの間の著作権問題に関する混乱と一致して、いくつかのフリーソフトウェアシェルの実装が行われました。 80年代後半から90年代前半にかけて。すべてのAlmquistシェル(ash、BSDのBourneシェルの代わりになります)、ksh(pdksh)、bash(FSF主催)、zshは1989年から1991.
Ashは、Bourneシェルの代わりになることを意図していましたが、ずっと後になるまでtypeが組み込まれていませんでした(NetBSD1.3およびFreeBSD2.3)。 )、ただしhash -vがありました。OSF/ 1 /bin/shにはtypeが組み込まれていました。 OSF / 1v3.xまでは0を返しました。bashはwhenceを追加しませんでしたが、iv id = “bcb57bbe4a”を追加しましたパスを出力するためのtypeの> オプション(type -pはwhence -p)および-aを使用して、一致するコマンドをすべて報告します。 tcshはwhichを組み込み、whereコマンドを追加してbash” s type -a。zshにはすべてがあります。
fishシェル(2005)には、関数として実装されたtypeコマンドがあります。
which cshスクリプトはNetBSDから削除され(tcshに組み込まれていて、他のシェルではあまり使用されていないため)、機能がwhereisに追加されました(which、whereisはwhichのように動作しますが、)。OpenBSDとFreeBSDでは、whichも$PATHでのみコマンドを検索するCで記述されたものに変更されました。 。
実装
which coの実装は数十あります。構文と動作が異なるさまざまなユニスのmmand。
Linuxの場合(tcshとzshの組み込みのもののほかに)いくつかの実装があります。たとえば、最近のDebianシステムでは、「$PATHでコマンドを検索する単純なPOSIXシェルスクリプトです。
busyboxにはwhichコマンドもあります。
GNU whichはおそらく最も贅沢なものです。which cshスクリプトが行ったことを他のシェルに拡張しようとします。エイリアスと関数が何であるかを教えて、与えることができます。あなたはより良い答えです(そして、いくつかのLinuxディストリビューションは、それを行うために、その周りにいくつかのグローバルエイリアスを設定していると思います)。
zshには、実行可能ファイルのパスに展開する演算子がいくつかあります。= ファイル名展開演算子と div id = “38f34b9ab5”> 履歴拡張修飾子(ここではパラメーター拡張に適用):
$ print -r -- =ls /bin/ls $ cmd=ls; print -r -- $cmd:c /bin/ls
zsh、モジュールは、コマンドハッシュテーブルをcommands連想配列として作成します:
$ print -r -- $commands[ls] /bin/ls
whatisユーティリティ(Unix V8BourneシェルまたはPlan9 rc / es)は、ドキュメント専用であるため、実際には関連していません(whatisデータベース、つまりmanページの概要を取得します)。
whereisも関連していました。 Cで記述されていても、whichと同時に3BSDに追加されました。 cshは、実行可能ファイル、マニュアルページ、およびソースを同時に検索するために使用されますが、現在の環境に基づくものではありません。繰り返しになりますが、これは別のニーズに応えます。
現在、標準的な面では、POSIXはcommand -vと-Vコマンド(POSIX.2008まではオプションでした)。 UNIXは、typeコマンドを指定します(オプションなし)。以上です(where、which、whenceはどの規格でも指定されていません) 。
一部のバージョンまで、typeとcommand -vは、Linux StandardBase仕様ではオプションでした。たとえば、poshのいくつかの古いバージョン(両方を持っていたpdkshに基づく)にはどちらもありませんでした。 command -vは、一部のBourneシェル実装(Solarisなど)にも追加されました。
今日の状況
今日の状況は、typeとcommand -vがすべてに遍在していることです。ボーンのようなシェル(ただし、@ jarnoで指摘されているように、POSIXモードでない場合、またはコメントで以下のAlmquistシェルの子孫である場合は、bashの警告/バグに注意してください)。 tcshは、whichを使用する唯一のシェルです(typeがあり、whichが組み込まれています。
tcshと、whichは、
、~/.bashrc、または任意のシェル起動ファイルで、ividに
$PATHを定義しない= “c92e1ab12d”> 。エイリアスまたは関数が定義されている場合、それについて通知する場合としない場合があります。または、間違ったことを通知する場合があります。
知りたい場合与えられた名前のすべてのコマンドについては、移植性のあるものは何もありません。 tcshまたはzsh、iv id = “9a534a3bbe”で、whereを使用します。 > bashまたはzsh、whence -aのksh93およびその他のシェル、typeをwhich -aと組み合わせて使用できます。
推奨事項
実行可能ファイルへのパス名の取得
スクリプトで実行可能ファイルのパス名を取得するには、いくつかの注意点があります。
ls=$(command -v ls)
これを行うための標準的な方法です。
ただし、いくつかの問題があります。
- 実行可能ファイルを実行せずにパスを知ることはできません。すべて
type、which、command -v…すべてヒューリスティックを使用してパスを見つけます。$PATHコンポーネントをループして、実行権限を持つ最初の非ディレクトリファイルを見つけます。ただし、depeシェルを見つけると、コマンドの実行に関しては、それらの多く(Bourne、AT & T ksh、zsh、ash …)は、次の順序で実行します。 は、execveシステムコールがエラーで返されないまで続きます。たとえば、$PATHに/foo:/barが含まれていて、lsを実行する場合、最初に試行されます。/foo/lsを実行するか、失敗した場合は/bar/lsを実行します。/foo/lsの実行は、実行権限がないために失敗する可能性がありますが、有効な実行可能ファイルではないなど、他の多くの理由もあります。/foo/lsの実行権限があるが、iv idを実行している場合、command -v lsは/foo/lsを報告します/foo/lsが有効な実行可能ファイルでない場合、= “d15a078f48”> は実際に/bar/lsを実行する可能性があります。 -
fooが組み込み、関数、またはエイリアスの場合、command -v fooはfooを返します。ash、pdksh、zshなどの一部のシェルでは、$PATHに空の文字列が含まれていて、現在のディレクトリに実行可能なfooファイルがある場合。これを考慮する必要がある場合があります。たとえば、組み込みのリストはシェルの実装によって異なることに注意してください(たとえば、mountはbusybox用に組み込まれている場合がありますsh)、たとえばbashは環境から関数を取得できます。 - if
$PATHには、シェルに応じて、相対パスコンポーネント(通常は.または空の文字列(どちらも現在のディレクトリを参照しますが、何でもかまいません))が含まれます。command -v cmdは絶対パスを出力しない可能性があるため、は、他の場所でcdを実行すると、無効になります。 - 事例:(正確なパスはシステムによって異なる可能性があります)
$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(
またはzsh)、command -ev(yashなど)、whatis -p(rc、akanga)または組み込みのwhich(tcshまたはzshなど)whichが存在するシステム利用可能であり、cshスクリプト。
これらの条件が満たされている場合:
echo=$(which echo)
最初のividのパスが表示されますechoがシェルであるかどうかに関係なく、$PATHの= “46435c0fe2”> (コーナーの場合を除く)組み込み/エイリアス/関数かどうか。
他のシェルでは、次のようにします。
- zsh :
echo==echoまたはecho=$commands[echo]またはecho=${${:-echo}:c} - ksh 、 zsh :
echo=$(whence -p echo) - yash :
echo=$(command -ev echo) - rc 、 akanga :
echo=`whatis -p echo`(スペースのあるパスに注意) - 魚:
set echo (type -fp echo)
実行するのが実行だけの場合は注意してください/ em>そのechoコマンド、パスを取得する必要はありません。次のようにするだけです。
env echo this is not echoed by the builtin echo
たとえば、tcshを使用して、組み込みのwhichが使用されないようにするには:
set Echo = "`env which echo`"
外部コマンドが必要な場合
whichを使用するもう1つのケースは、実際に必要な場合です。 外部コマンド。 POSIXでは、すべてのシェルビルトイン(commandなど)を外部コマンドとしても使用できる必要がありますが、残念ながら、commandには当てはまりません。多くのシステムで。たとえば、Linuxベースのオペレーティングシステムでcommandコマンドを見つけることはめったにありませんが、ほとんどのシステムには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を使用すると、そのトリックを使用する必要がなくなります。
コメント
- @ Joe、
whichは、多くの商用ユニスのcshスクリプトです。その理由は歴史的であり、’が私が歴史を与えた理由であり、人々はそれがどこから来たのか、なぜ人々がそれを使用することに慣れたのか、そしてなぜ実際にそこにあるのかを理解しています’それを使用すべき理由はありません。そして、はい、一部の人々は(t)cshを使用します。まだ誰もがLinuxを使用しているわけではありません - この投稿を読んだ後、答えのコンテキストはたくさん見つかりましたが、答え自体は見つかりませんでした。この投稿のどこに、
which9b39b47e6e “> を使用しない理由が実際に記載されています。 実行する、whichの履歴、whichの実装、関連タスクを実行するその他のコマンド、または実際に使用する理由which?他のコマンドが優れているのはなぜですか?whichとの違いは何ですか?彼らはどのようにしてその落とし穴を回避しますか?この回答は、実際には、whichの問題よりも代替案の問題に多くの単語を費やしています。 -
commandについて説明します。 POSIXによる。 - @St é faneChazelas
touch /usr/bin/mytestfileで新しいファイルを作成し、その後command -v mytestfile、パスを提供します(which mytestfileは提供しません)。 - @jarno、そうそう、あなた’正解です。
bashは、実行可能ファイルが見つからない場合、実行不可能なファイルに落ち着きます。’実行可能ファイルが見つからないため、’ s ” OK “(ただし、実際にはcommand -v/typeはエラーを返します)’は、mytestfileですが、dashの動作はバグがあり、’実行不可能なcmd実行可能ファイルの前にcommand -vは実行可能ファイルを返しますが、cmdを実行すると実行可能ファイルが実行されます(間違っています) 1つもハッシュされます)。 FreeBSDsh(これもashに基づく)にも同じバグがあります。 zsh、yash、ksh、mksh、bash asshはOKです。
回答
理由whichを使用したくないことはすでに説明されていますが、whichが実際に失敗するいくつかのシステムでのいくつかの例を次に示します。
Bourneのようなシェルでは、whichの出力をtype(typeはシェルに組み込まれているため、コマンドを呼び出す方法をシェルが示しているため、グラウンドトゥルースを意味します。
多くの場合はコーナーケースですが、which / typeはコーナーケースでよく使用されることに注意してください(答えを見つけるため)次のような予期しない動作に:なぜそのコマンドがそのように動作するのか、私はどちらを呼んでいるのですか?)。
ほとんどのシステム、ほとんどのBourneのようなシェル:関数
最も明白なケースは関数の場合です:
$ type ls ls is a function ls () { [ -t 1 ] && set -- -F "$@"; command ls "$@" } $ which ls /bin/ls
その理由は、whichは実行可能ファイルについてのみ報告し、場合によってはエイリアス(シェルのエイリアスであるとは限りません)についてのみ報告し、関数については報告しないためです。
manページの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は外部コマンドであるため、シェルにどのビルトインがあるか(および、bashまたはkshはビルトインを動的にロードできます):
$ 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、Tru645。 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
これは、ほとんどの商用ユニスではwhich(元の実装と同様)であるためです。 3BSD)は、~/.cshrcを読み取るcshスクリプトです。レポートされるエイリアスは、現在定義しているエイリアスや実際に使用しているシェルに関係なく、そこで定義されているエイリアスです。
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
(SolarisおよびAIXバージョンでは、~/.cshrc divを読み取る前に$pathを保存することで、この問題を修正しています。 >コマンドを検索する前に復元します)
$ 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、bash
$ 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コマンドをラップするシステム全体で定義されたエイリアスがあります。
偽の出力は、whichがbashのaliasしかし、それを適切に解析する方法がわからず、ヒューリスティックを使用します(1行に1つのエイリアス、|、、& …)
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ルックアップを無効にすることではなく、システムのデフォルトのPATH は残念ながらDebianで、誰も同意しません(dashとbashには/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin、zshには/bin:/usr/bin:/usr/ucb:/usr/local/bin、ksh93には/bin:/usr/bin、mkshには/usr/bin:/bin($(getconf PATH))、execvp()(envのように)には:/bin:/usr/binがあります(はい、最初に現在のディレクトリを調べます!)) 。
whichは、dashのデフォルトのividを使用しているため、上記で間違っているのはそのためです。 ksh93 “s
とは異なる=” ac187d6c45 “>
報告するGNUwhichの方が優れています:
which: no which in ((null))
(興味深いことに、確かには、実際にはakanga(rcデフォルトのPATHが/usr/ucb:/usr/bin:/bin:.))
bash、任意のシステムであるシェル派生物:
$ 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
whichでもtypeは、b/fooがbできないことを事前に知ることができますe実行されました。 iv id = “488253cbe9を呼び出す場合、bash、ksh、yashなどの一部のシェル”> は実際にb/fooを実行してエラーを報告しようとしますが、他の(zsh、、csh、Bourne、tcsh)が実行されますexecve()システムコールがb/fooで失敗した場合のdivid = “4234cc97bf”> 。
コメント
-
mkshは実際にはデフォルトの$PATHとは異なるものを使用しています。 、オペレーティングシステムのコンパイル時定数_PATH_DEFPATHが使用され(最も一般的にはBSDで)、次にconfstr(_CS_PATH, …)が使用されます(POSIX)、両方が存在しないか失敗した場合は、/bin:/usr/bin:/sbin:/usr/sbinが使用されます。 - 最初の例では、
lsはそれが使用している関数ですg PATHからls。また、whichは、/usr/bin/lsまたは/usr/local/bin/lsのどちらが使用されているかを示します。 ‘ “どの” ….を使用しないのかわかりません。 - @rudimeier、その
which lsは、lsに関係なく、/bin/lsを提供します。 div>関数は、/bin/lsまたは/opt/gnu/bin/lsまたはdirを呼び出すか、まったく呼び出しません。 IOW、which(実装、IMMV)は、無関係なものを提供しています - @St é phaneChazelas。ダメダメダメ。
lsが関数であることを知っています。ls関数がPATHdivからlsを呼び出していることを知っています >。これで、whichがファイルの場所を教えてくれます。単一のユースケースのみが表示されます:”このコマンドでシェルは何をしますか。”このユースケースの場合whichは間違っています、正しいです。ただし、(GNU)whichが正確に正しい場合もあります。 - @rudimeter、
whichの実装。 ‘がエイリアスであると言う人もいます(エイリアスが構成されている場合、または自宅に~/.cshrcがある場合そのようなエイリアス)、いくつかはあなたにパスを与えますが、いくつかの条件下では間違ったものです。sh -c 'command -v ls'ですが、完全ではありませんが、そのさまざまな要件に対する正しい答えが得られる可能性が高くなります(標準でもあります)。
回答
(私のクイックスキムから)ステファンが言及しなかったと思われることの1つは、whichがシェルのパスハッシュテーブルについてはわかりません。これには、実際に実行されているものを表していない結果が返される可能性があり、デバッグに効果がないという効果があります。
回答
whichでの根拠のないバッシングは誰にとっても役に立たないため、疑いを持たないユーザーにこの質問が推奨される場合、私は通常、うんざりします。
はうまく機能し、Unixのモトに従って、いくつかのタスクに正しい答えを提供します。 1つのことを実行し、うまく実行する、なぜwhichは禁止されますか?
では、どちらがうまく機能し、特定の仕事をうまく行うかという問題がありますか?
1つは、Debianの/ bin / whichにある外部ユーティリティです。は、パスに指定された名前の実行可能ファイルを一覧表示することだけを目的としたシェルスクリプトです。 whichは意図した目標を正しく実行していると思います。エイリアス、関数、シェルからの何もロードせず、PATHに指定された名前の最初の(またはすべての)実行可能ファイルをリストするだけです。 指定された名前と同じ名前のファイルを見つけたことを意味するは、ユーザーが彼女(彼)によって理解する必要があるものです。自己。
はい、他のwhich実装には特定の問題がある可能性があります(通常はあります)。
回答
避けるべきことをよく耳にします。どうして?代わりに何を使用すればよいですか?
聞いたことがありません。具体的な例を挙げてください。 whichの出所については、Linuxディストリビューションとインストールされているソフトウェアパッケージについて心配します!
SLES 11.4 x86-64
tcshバージョン6.18.01:
> which which which: shell built-in command.
bashバージョン3.2-147:
> which which /usr/bin/which > which -v GNU which v2.19, Copyright (C) 1999 - 2008 Carlo Wood. GNU which comes with ABSOLUTELY NO WARRANTY; This program is free software; your freedom to use, change and distribute this program is protected by the GPL.
whichは util-linux Linuxオペレーティングシステムの一部として使用するためにLinuxカーネル組織によって配布される標準パッケージ。また、これらの他のファイルも提供します
/bin/dmesg /bin/findmnt /bin/logger /bin/lsblk /bin/more /bin/mount /bin/umount /sbin/adjtimex /sbin/agetty /sbin/blkid /sbin/blockdev /sbin/cfdisk /sbin/chcpu /sbin/ctrlaltdel /sbin/elvtune /sbin/fdisk /sbin/findfs /sbin/fsck /sbin/fsck.cramfs /sbin/fsck.minix /sbin/fsfreeze /sbin/fstrim /sbin/hwclock /sbin/losetup /sbin/mkfs /sbin/mkfs.bfs /sbin/mkfs.cramfs /sbin/mkfs.minix /sbin/mkswap /sbin/nologin /sbin/pivot_root /sbin/raw /sbin/sfdisk /sbin/swaplabel /sbin/swapoff /sbin/swapon /sbin/switch_root /sbin/wipefs /usr/bin/cal /usr/bin/chrp-addnote /usr/bin/chrt /usr/bin/col /usr/bin/colcrt /usr/bin/colrm /usr/bin/column /usr/bin/cytune /usr/bin/ddate /usr/bin/fallocate /usr/bin/flock /usr/bin/getopt /usr/bin/hexdump /usr/bin/i386 /usr/bin/ionice /usr/bin/ipcmk /usr/bin/ipcrm /usr/bin/ipcs /usr/bin/isosize /usr/bin/line /usr/bin/linux32 /usr/bin/linux64 /usr/bin/look /usr/bin/lscpu /usr/bin/mcookie /usr/bin/mesg /usr/bin/mkzimage_cmdline /usr/bin/namei /usr/bin/rename /usr/bin/renice /usr/bin/rev /usr/bin/script /usr/bin/scriptreplay /usr/bin/setarch /usr/bin/setsid /usr/bin/setterm /usr/bin/tailf /usr/bin/taskset /usr/bin/time /usr/bin/ul /usr/bin/uname26 /usr/bin/unshare /usr/bin/uuidgen /usr/bin/wall /usr/bin/whereis /usr/bin/which /usr/bin/write /usr/bin/x86_64 /usr/sbin/addpart /usr/sbin/delpart /usr/sbin/fdformat /usr/sbin/flushb /usr/sbin/freeramdisk /usr/sbin/klogconsole /usr/sbin/ldattach /usr/sbin/partx /usr/sbin/rcraw /usr/sbin/readprofile /usr/sbin/rtcwake /usr/sbin/setctsid /usr/sbin/tunelp
私のutil-linuxはバージョン2.19です。リリースノートは、2007年8月28日付けのv2.13までさかのぼって簡単に見つけることができます。これのポイントまたは目標が何であったかはわかりませんが、331回賛成されたその長いものでは確かに答えられませんでした。
コメント
- どのように質問は、それが何を指しているのかについては言及していません。 Linuxは数少ないものの1つにすぎません。
-
which -vが示すように、’はGNUです(贅沢な1つは他の回答で言及されており、Linuxに固有のものではありません)、AFAIKにwhichユーティリティが含まれていなかったutil-linuxではありません。 util-linux 2.19は2011年のもので、GNUは2008年のものです。
whichの使用に反対するほとんどの議論は、インタラクティブなシェルコンテキストを想定していると思います。この質問には/ portabilityというタグが付けられています。このコンテキストでの質問は、”whichの代わりに、$PATH“。ほとんどの回答と理由whichは、エイリアス、ビルトイン、関数を扱います。これらは、ほとんどの実際のポータブルシェルスクリプトで学術的に関心があります。ローカルで定義されたエイリアスは、シェルスクリプトの実行時に’継承されません(.でソースを指定しない限り)。csh(およびwhichはほとんどの商用でまだcshスクリプトですUnices)は、非対話型の場合、~/.cshrcを読み取ります。そのため、’ ‘ cshスクリプトは通常#! /bin/csh -fで始まることに気付くでしょう。whichは、エイリアスを提供することを目的しているためではありません。これは、’が(インタラクティブ)cshのユーザー。 POSIXシェルユーザーはcommand -vを持っています。(t)cshでない限り、答えは常にになります。 div>(または、’正しい結果が得られなくても’気にしないでください)、またはcommand -v。 理由の回答を参照してください。stat $(which ls)はいくつかの理由で間違っています(、引用符がありません)、which)の使用法だけではありません。 ‘stat -- "$(command -v ls)"を使用します。これは、lsが実際にファイルシステムにあるコマンドであることを前提としています(シェルの組み込みやエイリアスの機能ではありません)。whichが間違ったパス(lsを入力した場合にシェルが実行するパスではない)を提供したり、定義されたエイリアスを提供したりする可能性があります他のいくつかのシェルの構成では…whichの実装でさえも得られない条件がいくつかあります。lsは、$PATHのルックアップによって検出されます(lsに関係なくシェルで呼び出すことができます)。sh -c 'command -v ls'またはzsh -c 'rpm -q --whatprovides =ls'が正しい答えを与える可能性が高くなります。ここでのポイントは、whichはcshからの壊れた遺産であるということです。