実行可能ファイルが見つからない場合、「which」の実装は「no」を出力しますか?

実行可能ファイルが見つからない場合、「which」の実装は「no」を出力しますか?

私が読んでいるBourneシェル用に作成されたMavenラッパーのソースコード。私は次の内容を見つけました。

if [ -z "$JAVA_HOME" ]; then
    javaExecutable="$(which javac)"
    if [ -n "$javaExecutable" ] && ! [ "$(expr "$javaExecutable" : '\([^ ]*\)')" = "no" ]; then
# snip

exprarg1andと一緒に使用すると、arg2aは正規表現と一致します:。通常、結果は一致する文字の数です。たとえば、次のようになります。arg1arg2

$ expr foobar : foo
3

ただし、キャプチャ括弧(\(および\))を使用すると、最初のキャプチャ括弧の内容が返されます。

$ expr foobar : '\(foo\)'
foo

今まではそんなに良くなった。

上記で引用したソースの式を自分のコンピュータで評価すると、次のような結果が得られます。

$ javaExecutable=$(which javac)
$ expr "$javaExecutable" : '\([^ ]*\)'
/usr/bin/javac

存在しない実行可能ファイルの場合:

$ nonExistingExecutable=$(which sjdkfjkdsjfs)
$ expr "$nonExistingExecutable" : '\([^ ]*\)'

つまり、存在しない実行可能ファイルの場合、出力は改行を含む空の文字列です。

which javacソースコードで私を混乱させるのは、arg1(to)の出力がexpr文字列を返す方法ですno

which何も返しませんが、実行可能ファイルが見つからないときに返すバージョンはありますか?no

そうでなければ、このステートメントは常に真と評価され、これは奇妙です。

答え1

伝統的にエラーメッセージを印刷して成功ステータスを返すwhichcshスクリプト。no foo in /usr/bin:/bin(少なくとも1つの共通バージョンがあり、動作が異なるバージョンがある可能性があります。)はいFreeBSD 1.0で起動(はい、それは古代です):

    if ( ! $?found ) then
    echo no $arg in $path
    endif

(この古典的な実装は、ユーザーのロードにも悪名高いです.cshrc。これは変更され、PATH誤った出力を引き起こす可能性があります。)

最新のシステムは、一般的にCまたはshで書かれたさまざまな実装を持ち、whichエラー条件処理の最新の標準に従います。つまり、stdoutに出力されず、終了状態が0ではありません。

答え2

技術的には、これは次の点を確認するチェックです。最初の単語(または空白以外の文字の最初のシーケンス)を出力します。そして、いくつかのwhich実装は沈黙しません。

  • zshwhich foo標準foo not found出力に書き込む
  • GNUはstderrwhich fooに書き込みます。which: no foo in (<contents of $PATH>)
  • テストする項目はありませんが、以前のUnixのマンページには、「引数名を持つ実行可能ファイルがパスに見つからない場合は診断情報を印刷します」というフレーズがあります。標準エラー)。

印刷物で始まる特定のバリエーションが何であるかはわかりませんが、noGNUはwhichこのバリエーションからインスピレーションを受けたかインスピレーションを受けた可能性があります。

関連情報