サポートされていない "shopt"オプションが.bashrcでエラーを引き起こすのを防ぐにはどうすればよいですか?

サポートされていない "shopt"オプションが.bashrcでエラーを引き起こすのを防ぐにはどうすればよいですか?

私は、異なるHPCノード、仮想マシン、またはプライベートワークステーションで異なるバージョンのBashを実行できる比較的異質な環境で働いています。ログインスクリプトをGitリポジトリに入れたので、.bashrc「このホストなら...」と同じタイプの混乱なしに、全体的に同じスクリプトを使用したかったのです。

良いBash 4.1 以下の基本動作は、キーを押したときの動作cd $SOMEPATHに拡張されました。 Bash 4.2以降では、この動作を再度有効にする必要があります。cd /the/actual/pathTabshopt -s direxpandそれない2029年2月4日まで。ただし、これは単なる例であり、関連性がある可能性がある別のshoptオプションcomplete_fullquoteです。正確にその効果)はv4.2のデフォルト動作を変更することもできます。

ただし、direxpand以前のバージョンのBashは認識されず、私がshopt -s direxpandこれを試みると、.bashrc以前のバージョンのBashを使用してノードにログインするたびにコンソールにエラーメッセージが表示されます。

-bash: shopt: direxpand: invalid shell option name

私がしたいのは、shop -s direxpand以前のバージョンのBashに影響を与えずに、強力な方法でBash> 4.1でオプションを有効にする条件をラップすることです(つまり、エラー出力を)にリダイレクトするわけではありません/dev/null

答え1

エラーにリダイレクトするのは理解できません/dev/null。コードを強力にするには、set -e次の一般的なイディオムを使用してください… || true

shopt -s direxpand 2>/dev/null || true

オプションがない場合にいくつかの代替コードを実行するには、次の戻り状態を使用してくださいshopt

if shopt -s direxpand 2>/dev/null; then
  … # the direxpand option exists
else
  … # the direxpand option does not exist
fi

ただし、リダイレクトエラーが本当に気に入らない場合は、完了メカニズムを使用してセルフチェックを実行できます。これはbash 2.03以下で、プログラム可能な完了機能を持たない古いシステムがないと仮定します。

shopt_exists () {
  compgen -A shopt -X \!"$1" "$1" >/dev/null
}
if shopt_exists direxpand; then
  shopt -s direxpand
fi

この方法は、一部の環境(Cygwinなど)で遅い分岐を防ぎます。シンプルなので2>/dev/null性能面では勝てないと思います。

答え2

direxpand出力に存在することを確認し、shopt存在する場合はアクティブにします。

shopt | grep -q '^direxpand\b' && shopt -s direxpand

答え3

特定の人を識別するときshoptオプションBashの一部のメジャー/マイナー/パッチバージョンで使用でき、$BASH_VERSION変数または配列の要素を確認して条件付きで$BASH_VERSINFO[]アクティブにすることができます。

これはBash 4.2.29以降のテストです。direxpand 初めて紹介された4.2シリーズの場合:

if [[ $BASH_VERSION == 4.2.* && ${BASH_VERSINFO[2]} -ge 29 ]] ||
   [[ ${BASH_VERSINFO[0]} -eq 4 && ${BASH_VERSINFO[1]} -ge 3 ]] ||
   [[ ${BASH_VERSINFO[0]} -ge 5 ]]; then
    shopt -s direxpand
fi

編集する:明らかに、これはログインスクリプトのエラーメッセージを単に無視するための過度のエンジニアリングソリューションですが、とにかく私の参照のために記録したいと思いました。

周囲の中括弧に注意してください。${BASH_VERSINFO[index]}はい(ロケールによる)語彙比較の代わりに整数を実行するためのandの-eq使用も必要です。-gt引用しない場合、演算子のRHSは、前述のように、Bash /条件で「extglob」パターン==として扱われます。[[]]ここ、これは正規表現IMOよりも美しい「スタート」比較を提供します。

これ$BASH_VERSINFO大量に次の出力に表示されるすべての情報が含まれていますbash --version

bash --version | head -1
# result:
# GNU bash, version 4.3.48(1)-release (x86_64-pc-linux-gnu)

declare -p BASH_VERSINFO
# result:
# declare -ar BASH_VERSINFO='([0]="4" [1]="3" [2]="48" [3]="1" [4]="release" [5]="x86_64-pc-linux-gnu")'

いついいえshoptLucianoが提案したアプローチが良いというBashバージョンがサポートされているか、動作が変更された文書で明らかです。

# note the '-q' so that the matched pattern isn't actually printed
shopt | grep -q direxpand && shopt -s direxpand

...Gillesが提案した解決策のように、エラー()を無視して必要があることをshopt -s direxpand 2>/dev/null確認してください。$?

引用:12サム
関連読書:スーツと買い物、なぜ二人ですか?

関連情報