Nounsetシェルオプションを使用してBash 4.2より前のバージョンに変数が定義されているかどうかをテストするにはどうすればよいですか?

Nounsetシェルオプションを使用してBash 4.2より前のバージョンに変数が定義されているかどうかをテストするにはどうすればよいですか?

-v「GNU bash、バージョン4.2」より前のBashバージョンにこのコマンドオプションと同等の選択肢はありますかtest?たとえば、

shopt -os nounset
test -v foobar && echo foo || echo bar
# Output: bar
foobar=
test -v foobar && echo foo || echo bar
# Output: foo

答え1

すべてのPOSIXシェルに移植可能:

if [ -n "${foobar+1}" ]; then
  echo "foobar is defined"
else
  echo "foobar is not defined"
fi

${foobar:+1}foobar空であっても定義されていなくても、同じ方法で処理するには、そうします。定義されていない${foobar-}場合は空の文字列を取得するためにfoobar使用することができます。そうでない場合は値を取得するために使用することもできfoobarます-

kshでは、foobar宣言されているが定義されていない場合は空の文字列に展開されますtypeset -a foobar${foobar+1}

Zsh変数は宣言されていませんが、設定されていません。typeset -a foobar空の配列を作成します。

Bashでは、配列はさまざまで驚くべき方法で動作します。空でない配列の場合にのみ${a+1}拡張されます。1a

typeset -a a; echo ${a+1}    # prints nothing
e=(); echo ${e+1}            # prints nothing!
f=(''); echo ${f+1}          # prints 1

同じ原則が連想配列に適用されます。配列変数に空でないインデックスセットがある場合、配列変数は定義された配列変数と見なされます。

どのタイプの変数が定義されているかをテストする別のbash関連の方法は、その変数がundefedとして報告されていることを確認することです。${!PREFIX*}${foobar+1}unset foobar; typeset -a foobar

case " ${!foobar*} " in
  *" foobar "*) echo "foobar is defined";;
  *) echo "foobar is not defined";;
esac

これは次のとおりです。typeset -p foobarまたはの戻り値をテストします。declare -p foobarしかし、typeset -p foobar宣言されているが割り当てられていない変数では失敗します。

bashでは、kshと同様にset -o nounset; typeset -a foobar; echo $foobar未定義の変数を拡張しようとするとエラーが発生しますfoobar。 kshとは異なり、set -o nounset; foobar=(); echo $foobar(またはecho "${foobar[@]}")もエラーを引き起こします。

ここで説明されているすべてのケースで以下のエラーが発生した${foobar+1}場合にのみ、空の文字列への拡張が行われます。$foobarset -o nounset

答え2

Gilesの答えをまとめて、次のルールを開発しました。

  1. [[ -v foobar ]]Bashバージョン> = 4.2で使用される変数。
  2. declare -p foobar &>/dev/nullBash バージョン < 4.2 で使用するための配列変数です。
  3. (( ${foo[0]+1} ))または、(( ${bar[foo]+1} ))インデックス配列(-a)とキー-A配列()declareの下付き文字としてそれぞれ使用します。オプション1と2はここでは機能しません。

答え3

Bashのすべての変数に同じ技術を使用して動作します。たとえば、次のようになります。

[ ${foobar} ] && echo "foobar is set" || echo "foobar is unset"

出力:

foobar is unset

同時に

foobar=( "val" "val2" )
[ ${foobar} ] && echo "foobar is set" || echo "foobar is unset"

出力:

foobar is set

関連情報