$PATH
bash / ksh / zshで見つけることができる(またはシェルから呼び出すことができる)代替リストの最初の変数を設定する良いイディオムはありますか?
たとえば、動作する必要があるスクリプトがある場合実際のパス(1)下に設置しrealpath
たり、grealpath
長い道のりを行くことができます:
if type "grealpath" > /dev/null; then
realpath_exec=grealpath
elif type "realpath" > /dev/null; then
realpath_exec=realpath
else
echo "$0: No realpath found in PATH" >&2
exit 1
fi
式を書くために私が考えることができる||
ほとんどの方法は、入れ子に&&
なったサブシェル(大きな問題ではなく、頻繁に呼び出される関数のパフォーマンスに悪くも面倒です)および/またはさまざまな出力を処理するための複雑なgrep
リダイレクトまたは醜さを必要としますします。 (参考にしてください、出力インストールされている「プログラム」が関数またはエイリアスの場合は、type
直接使用できます。which
したがって、操作を実行するために何かを呼び出すことができると仮定するには、realpath
出力または別名の代わりに戻り値をオンにする必要があります。 grepをやってみてください。 )
上記の内容は素晴らしいです。そのようなプログラムに複数のオプションがある場合は、時間がかかり、苦痛です。もっとありますか?エレガントリストから最初に利用可能なプログラムを選択して変数に割り当てることはできますか?
ベストアンサー1
最も簡単でわかりやすいのは、for
内部にif
sがあるループであり、break
一致するものを見つけるとループから抜け出します。
これをしたくない場合は、Bashでtype
複数のパラメータを受け入れます。探す:
type grealpath realpath ...
一致する項目の出力行の最初の単語は、常に1コマンド/関数/エイリアスの名前です。追加のサブプロセスを避けるために、配列のstdoutをキャプチャしてインデックス化できます。
words=($(type realpath grealpath foo make 2>/dev/null))
realpath_exec=${words[0]}
if ! [ "$realpath_exec" ] ...
これはいくつかの観点からはエレガントですが、偶然発見した場合は明らかに理解するのがより困難です。
配列イニシャライザのトークン化に依存するの価値IFS
。IFS
これが変更された場合、またはコマンドにスペースが含まれている場合は機能しません。
1実験によると、そうです。最大ロケールは自然な語順ではなくても、常に U+0020 ASCII スペースが続きますが、出力形式は指定されなくなりました。一部のローカライズではこれは機能しません。これが問題を引き起こすかどうかを考慮する必要があります。LC_ALL=C type ...
(多少)適切であると保証された出力フォーマットを使用できます。
zshから、関数やエイリアスではなく実行可能ファイルにのみ興味がある場合は、次のようにします。$commands
:
realpath_exec=${commands[grealpath]:-${commands[realpath]:-${commands[another]:?No compatible command found}}}
拡張はnullでない場合は値を提供し${param:-...}
、それ以外の場合はエラーが発生します。これはまだ非常に醜いです。param
...
${param:?...}
...
param
コマンド選択の間の順序に気にしない場合は、より単純なバージョンを使用できます(i) 下付き文字の表示:
realpath_exec=${commands[(i)realpath|grealpath|another]}
関数とエイリアスを含めるには、$functions
andを使用できますが、$aliases
繰り返します。