サポートされていない「ショップ」オプションが.bashrcでエラーを発生させないようにするにはどうすればよいですか?


9

さまざまなバージョンのBashをさまざまなHPCノード、VM、または個人用ワークステーションで実行している可能性がある、比較的異種の環境で作業しています。私はログインスクリプトをGitリポジトリに配置しているので.bashrc、「もしこのホストなら...」タイプの面倒さをあまり使わずに、同じように全面的に使用したいと思います。

のようなバッシュ≤拡大し4.1のデフォルトの動作cd $SOMEPATHcd /the/actual/path押したときにTabキーを。バッシュ4.2以上では、あなたがする必要があるだろうshopt -s direxpandし、この動作を再度有効にし、それが利用可能になっていませんでした4.2.29まで。ただし、これはほんの一例です。別の、おそらく関連するshoptオプションcomplete_fullquote(それが何をするのか正確にはわかりませんが)もv4.2でデフォルトの動作を変更した可能性があります。

ただし、direxpand以前のバージョンのBashでは認識されないためshopt -s direxpand、自分のを使用しようとする.bashrcと、古いBashのノードにログインするたびにエラーメッセージがコンソールに出力されます。

-bash: shopt: direxpand: invalid shell option name

私は何をしたいのは、条件付きの周りをラップでshop -s direxpandバッシュの旧バージョン(擦れずに、堅牢な方法でバッシュ> 4.1にそのオプションを有効にするには、すなわち、ちょうどにエラー出力をリダイレクトしません/dev/null)。


どのように私の答えは役に立たなかったのですか?
Luciano Andress Martini

@LucianoAndressMartiniそれはそうでした、そしてそれは私が自分自身で最終的に行った解決策.bashrcです。$BASH_VERSINFO私自身の啓蒙のために、実行中のシェルのメジャー/マイナーバージョンを調べる方法を記録したかったので、自分の回答を投稿しました。:)
TheDudeAbides

私の答えを見てください私はプログラムのバージョンをシェルスクリプトと比較することについて何かを持っています。
Luciano Andress Martini

回答:


14

direxpandの出力に存在するかどうかを確認し、存在する場合はshopt有効にします。

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

4
ことを改善するgrep -q '^direxpand\b'場合にはbashのいくつかの将来のバージョンやフォーク列としてこれを含んでいるオプションがある削除しをdirexpand。この特定のケースではありそうにありませんが、堅牢であるためにそれほどコストはかかりません。
Gilles「SO-悪をやめる」

ルチアーノに感謝します。私は自分の質問に答えるつもりでしたが、私の編集がピアレビューを通過した後で私はあなたの答えを受け入れます。たぶん、あなたはそれらを自分で承認できますか?
TheDudeAbides

4
Bashでは特定のシェルオプションを照会できるため、を使用できます[ -z "$(shopt -po direxpand 2>&-)" ] || shopt -s direxpand。これ以上の正規表現の問題はありません!:-)
デビッド・フォースター

@DavidFoerster私は論理を逆転させ[ -n "blah" ] && shopt blahます:言い方は、「direxpandがサポートされていない場合は、このことを行わないでください」と言っています。
リッチ

1
@リッチ:ほとんどのシェルスクリプトはset -e先頭に含まれるため、この方法でショートカットロジックを使用する傾向があります。
David Foerster、

16

エラーをにリダイレクトする際の問題がわかりません/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こともそうですが、パフォーマンスでそれを打ち負かすことはできないと思います。


それは私の脳が消えた場所ではありませんが、私はcompgen提案が好きです。それはまさにそこの大学レベルのものです!へのリダイレクトを回避すること/dev/nullは、単なる個人的な好みです。それが理にかなっている場合、私は許しの代わりに許可を求めるのが好きですか?:)
TheDudeAbides

+1は、Bashのプログラム可能な完了でまったく予期しない教育を受けたcompgen -A shopt -X ...ことを意味します。
TheDudeAbides

4
@TheDudeAbides私がUnixとLinuxcompgenこの方法を使用することについて読んだのですが、誰が最初に提案したのかわかりません。(プログラムで完了する前に、bashをメインシェルとして使用することをやめました。)プログラミングでは、コーディングのために、アクセス許可のチェックが実際に行っていることと一致しないリスクがあるため、通常、アクセス許可を求めることはお勧めできません。エラー(あなたがチェックしていると思うものを完全にチェックしていない場合)またはそれを使用する前にチェックし内容が変更されたため
Gilles 'SO-悪をやめる'

5

Bashの特定のメジャー/マイナー/パッチリリースで特定のshoptオプションが利用できることが確実にわかっている場合は、$BASH_VERSION変数または$BASH_VERSINFO[]配列の要素を調べて、条件付きで有効にすることができます。

以下は、4.2シリーズdirexpand に初めて導入されたバージョンであるBash 4.2.29以降のテストです。

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

編集:明確にするために、これはログインスクリプトからのエラーメッセージを単に無視するためのばかばかしく過剰に設計されたソリューションですが、私自身の啓発のために、それを文書化したいと思いました。

周りの括弧注、されている必要があり、の使用及び(ロケールに依存する)の語彙の比較ではなく整数で行います。引用符で囲まれていない場合、演算子のRHSは、ここで説明するように、Bash / 条件文内で「extglob」パターンとして扱われます。これにより、正規表現のIMOよりも美的「開始」比較が美しくなります。${BASH_VERSINFO[index]}-eq-gt==[[]]

$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")'

Bashのバージョンがサポートされるようになった、または動作が変更されたドキュメントが明確でない場合shopt、Lucianoが提案した方法で問題ありません

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

...エラー(shopt -s direxpand 2>/dev/null)を無視し、おそらく$?絶対に必要かどうかをチェックするだけでGillesによって提案された解決策と同様です。

参考文献:123
関連読書:セットとShopt -なぜ二つ?


また、のようなものを使用することができるかもしれませんif [[ $BASH_VERSION > 4.3 ]];(その試合4.3.05.0などが、また4.3.0-alpha後で、実際の問題ならば、私は知りません。)
ilkkachu

@ilkkachuさん、こんにちは。Bash v5.xをカバーするための編集に感謝します。direxpandただし、このオプションはBash 4.2で実際に使用できます。実行することで、v4.2.53のDockerイメージでこれを確認しましたdocker run --rm bash:4.2 bash -c shopt | grep direxpand(そして、適切な方法として、実行すると、v4.1.17では実際に使用できなくなりますdocker run --rm bash:4.1 bash -c shopt | grep direxpand)。
TheDudeAbides

ああ、わかった。私はテスト4.2.0して、そこで機能しないという事実に出会った。変更ログには、で追加されbash-4.3-alphaたことが記載されています。${BASH_VERSINFO[2]}それについては、正確に確認する必要があると思いますが、どのポイントリリースで追加されたかはわかりません...
ilkkachu

基本的に、Gillesが上記で指摘した点を証明したと思います。実際には、より良いだけであることを試みるシェルオプションを有効にして、エラーに対処する(またはそれを抑制)、それがサポートされていない場合。
TheDudeAbides
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.