変数がBashで設定されているかどうかを確認するにはどうすればよいですか?


1567

変数がBashで設定されているかどうかを確認するにはどうすればよいですか?

たとえば、ユーザーが関数に最初のパラメーターを指定したかどうかを確認するにはどうすればよいですか?

function a {
    # if $1 is set ?
}

12
if test $# -gt 0; then printf 'arg <%s>\n' "$@"; fi
イェンス

210
ソリューションを求めるユーザーへの注意:「空ではない変数である」という質問に答える、この質問に対する多くの高評価の回答があります。より多くの修正ソリューション(「変数セットです」)は、以下のイェンスとライオネルの回答で言及されています。
Nathan Kidd

8
また、Russell HarmonとSeamusは-vテストに問題はbashありませんが、これは新しいバージョンのでのみ利用可能で、シェル間での移植性はないようです。
Graeme 2014年

5
@NathanKiddが指摘したように、LionelとJensが正しい解決策を提供しています。prosseek、あなたはこれらのいずれかにあなたの受け入れられた答え切り替えるべきです。
ギャレット

3
...または、@ prosseekが問題に対処していないため、私たちの間でより目の肥えた人が間違った答えを投票する可能性があります。
dan3 2014

回答:


2305

(通常)正しい方法

if [ -z ${var+x} ]; then echo "var is unset"; else echo "var is set to '$var'"; fi

どこに${var+x}あるパラメータ展開ならば何にも評価されvar設定されていない、との文字列を置換しxそう。

余談

この構文と使用法は、引用符を必要としないものにのみ展開されるため、引用符は省略できます(そのため、${var+x}代わりにと言います)。何もありません(結果として、便利に同じ値(true)に評価されます)))。"${var+x}"x[ -z ][ -z "" ]

ただし、引用符は安全に省略でき、すぐには明らかではありませんでしたが(主要なBashコーダーでもあるこの引用符の説明の筆頭著者にも明らかではありませんでした)、ソリューションを記述する方が良い場合があります引用符付き[ -z "${var+x}" ] O(1)速度のペナルティの非常に小さい可能なコストで、。最初の著者も、このソリューションを使用してコードの横にコメントとしてこれを追加し、この回答へのURLを提供しています。これには、引用符を安全に省略できる理由の説明も含まれています。

(しばしば)間違った方法

if [ -z "$var" ]; then echo "var is blank"; else echo "var is set to '$var'"; fi

設定されていない変数と空の文字列に設定されている変数を区別しないため、これはしばしば間違っています。つまり、var=''、上記のソリューションは「var is blank」を出力します。

unsetと "set to the empty string"の区別は、ユーザーが拡張子またはプロパティの追加リストを指定する必要があり、それらを指定しないとデフォルトで空でない値になり、空の文字列を指定する必要がある場合に不可欠です。スクリプトが空の拡張子または追加のプロパティのリストを使用するようにします。

ただし、区別はすべてのシナリオで必須ではありません。これらの場合 [ -z "$var" ]は問題ありません。


29
@Garrett、あなたの編集がこの答えを正しくないようにしました、${var+x}使用する正しい置換です。を使用[ -z ${var:+x} ]してもと同じ結果が得られ[ -z "$var" ]ます。
Graeme

11
これは機能しません。varが値に設定されているかどうかに関係なく、「未設定」になります(「unset var」でクリアすると、「echo $ var」は出力を生成しません)。
Brent212 2014

10
ソリューションの構文$ {parameter + word}の場合、公式のマニュアルセクションはgnu.org/software/bash/manual/…です。ただし、そのバグのため、この構文はあまり明確に言及されていませんが、ただquote(colon [":"]を省略すると、設定されていないパラメーターのみのテストになります。.. $ {parameter:+ word} [手段]パラメータがnullまたは未設定の場合、何も置換されません。それ以外の場合、単語の展開が置換されます。); 引用されたrefpubs.opengroup.org/onlinepubs/9699919799/utilities/…(知っておきたい)には、ここにもっと明確なドキュメントがあります。
Destiny Architect

7
複数の式を使用する場合は引用符が必要なようです。たとえば、bash 4.3-ubuntu(zshなどではない)で[ -z "" -a -z ${var+x} ]取得bash: [: argument expectedします。たまに機能する構文を使用した答えは本当に嫌いです。
FauxFaux 2015年

41
シンプルを使用すること[ -z $var ]は、引用符を省略することと同じです。いずれにせよ、あなたはあなたの入力について仮定をしている。空の文字列を未設定として扱う場合は、これで十分[ -z $var ]です。
nshew 2016

910

非ヌル/非ゼロ文字列変数を確認するには、つまり設定されている場合は、次を使用します。

if [ -n "$1" ]

の逆です-z。私はを-n超えて使用しています-z

次のように使用します。

if [ -n "$1" ]; then
  echo "You supplied the first parameter!"
else
  echo "First parameter not supplied."
fi

86
より強力で特定の状況で問題が少ないため、通常はを優先[[ ]]します(2つの違いの説明については、この質問を参照してください)。この質問は特にbashソリューションを要求し、移植性の要件については触れていません。[ ][[ ]]
フロー

18
問題は、変数が設定されているかどうかを確認する方法です。その場合、変数設定されているとは想定できません。
HelloGoodbye 2013年

7
私は同意し、[]特にシェル(非bash)スクリプトでよりよく機能します。
Hengjie 2014年


63
これ-nはデフォルトのテストなので、より簡単に、[ "$1" ]または[[ $1 ]]同様に機能します。また、[[ ]] 引用は不要です。
2014年

478

ここではどのようにテストにだパラメータがあるかどうかを設定しない、または空(「ヌル」)または値のセット

+--------------------+----------------------+-----------------+-----------------+
|   Expression       |       parameter      |     parameter   |    parameter    |
|   in script:       |   Set and Not Null   |   Set But Null  |      Unset      |
+--------------------+----------------------+-----------------+-----------------+
| ${parameter:-word} | substitute parameter | substitute word | substitute word |
| ${parameter-word}  | substitute parameter | substitute null | substitute word |
| ${parameter:=word} | substitute parameter | assign word     | assign word     |
| ${parameter=word}  | substitute parameter | substitute null | assign word     |
| ${parameter:?word} | substitute parameter | error, exit     | error, exit     |
| ${parameter?word}  | substitute parameter | substitute null | error, exit     |
| ${parameter:+word} | substitute word      | substitute null | substitute null |
| ${parameter+word}  | substitute word      | substitute word | substitute null |
+--------------------+----------------------+-----------------+-----------------+

出典:POSIX:Parameter Expansion

「substitute」で示されているすべてのケースで、式は示されている値で置き換えられます。「assign」で示されるすべてのケースで、パラメーターにはその値が割り当てられ、式も置き換えられます。

これを実際に表示するには:

+--------------------+----------------------+-----------------+-----------------+
|   Expression       |  FOO="world"         |     FOO=""      |    unset FOO    |
|   in script:       |  (Set and Not Null)  |  (Set But Null) |     (Unset)     |
+--------------------+----------------------+-----------------+-----------------+
| ${FOO:-hello}      | world                | hello           | hello           |
| ${FOO-hello}       | world                | ""              | hello           |
| ${FOO:=hello}      | world                | FOO=hello       | FOO=hello       |
| ${FOO=hello}       | world                | ""              | FOO=hello       |
| ${FOO:?hello}      | world                | error, exit     | error, exit     |
| ${FOO?hello}       | world                | ""              | error, exit     |
| ${FOO:+hello}      | hello                | ""              | ""              |
| ${FOO+hello}       | hello                | hello           | ""              |
+--------------------+----------------------+-----------------+-----------------+

5
@HelloGoodbyeはい、機能しset foo; echo ${1:-set but null or unset}ます。「foo」をエコーし​​ます。set --; echo ${1:-set but null or unset}エコーが設定されていますがnull ...
イェンス

4
@HelloGoodbye位置パラメータは、ええと、set:-)で設定できます
Jens

95
この答えは非常に混乱します。このテーブルの使用方法に関する実際的な例はありますか?
ベンデイビス

12
@BenDavis詳細は、POSIX標準へのリンクで説明されています。POSIX標準は、表が引用されている章を参照しています。私が作成するほとんどすべてのスクリプトで使用する構造の1つ: ${FOOBAR:=/etc/foobar.conf}は、変数が設定されていないかnullの場合、変数のデフォルト値を設定することです。
Jens

1
parameter変数名です。 word使用しているテーブルの構文、および変数$parameterが設定されているか、設定されているがnullであるか、設定されていないかに応じて、置換する文字列です。複雑にするためでwordはなく、変数を含めることもできます!これは、文字で区切られたオプションの引数を渡すのに非常に役立ちます。例: 設定されているがnullではない場合${parameter:+,${parameter}}、コンマ区切りで出力し,$parameterます。この場合、wordある,${parameter}
TrinitronX

260

ここで述べられているテクニックのほとんどは正しいですが、bash 4.2は変数の値をテストするのではなく、変数の存在の実際のテスト(man bash)をサポートしています。

[[ -v foo ]]; echo $?
# 1

foo=bar
[[ -v foo ]]; echo $?
# 0

foo=""
[[ -v foo ]]; echo $?
# 0

特に、set -u/ set -o nounsetなどの多くのアプローチとは異なり、/ モードで設定されていない変数を確認するためにこのアプローチを使用しても、エラーは発生しません[ -z


9
bash 4.1.2では、変数が設定されているかどうかに関係なく、[[ -v aaa ]]; echo $?==>-bash: conditional binary operator expected -bash: syntax error near 'aaa'
Dan

32
'test'ビルトインへの '-v'引数はbash 4.2で追加されました。
Ti Strga 2014年

19
-v引数は、-uシェルオプション(nounset)を補完するものとして追加されました。'nounset'をオン(set -u)にすると、対話型でない場合、シェルはエラーを返して終了します。$#は、位置パラメータをチェックするのに適していました。ただし、名前付き変数は、それらが未設定であることを識別するために、妨害以外の方法が必要でした。多くの人が以前のバージョンと互換性があることにバインドされているため、この機能があまりにも遅くなって残念ですが、その場合は使用できません。他の唯一のオプションは、上に示したようにそれを回避するためにトリックまたは「ハック」を使用することですが、それは最も洗練されていません。
osirisgothra 2014

2
これは、宣言されているが設定されていない変数では機能しないことに注意してください。例declare -a foo
miken32

17
これが、私が受け入れられた/最高投票の回答の後に読み続ける理由です。
Joe

176

これを行うには多くの方法があり、次のものがその1つです。

if [ -z "$1" ]

$ 1がnullまたは未設定の場合、これは成功します


46
未設定のパラメーターとnull値のパラメーターには違いがあります。
chepner 2013年

21
私は知識を深めたいだけであり、これは質問が提起するものに対する反対の答えであることを指摘します。質問は、変数が設定されているかどうかではなく、変数が設定されているかどうかを尋ねます。
Philluminati 2013年

47
[[ ]]移植性の落とし穴にすぎません。if [ -n "$1" ]ここで使用する必要があります。
イェンス

73
この答えは間違っています。この質問では、変数が設定されているかどうかを確認する方法が求められます。空でない値に設定されているかどうかは確認されません。与えられたfoo=""$foo値を持っていますが、-z単にそれが空だことを報告します。そして、-z $fooあなたが持っている場合は爆破されますset -o nounset
キーストンプソン

4
「変数を設定する」の定義による。変数がゼロ以外の文字列に設定されているかどうかを確認する場合は、mbranning回答が正しいです。しかし、変数が宣言されているが初期化されていない(つまりfoo=)かどうかを確認したい場合、ラッセルの答えは正しいです。
フロー

77

私はいつも他の答えでPOSIXテーブルを見つけるのが遅いので、ここでそれを私の見解とします:

   +----------------------+------------+-----------------------+-----------------------+
   |   if VARIABLE is:    |    set     |         empty         |        unset          |
   +----------------------+------------+-----------------------+-----------------------+
 - |  ${VARIABLE-default} | $VARIABLE  |          ""           |       "default"       |
 = |  ${VARIABLE=default} | $VARIABLE  |          ""           | $(VARIABLE="default") |
 ? |  ${VARIABLE?default} | $VARIABLE  |          ""           |       exit 127        |
 + |  ${VARIABLE+default} | "default"  |       "default"       |          ""           |
   +----------------------+------------+-----------------------+-----------------------+
:- | ${VARIABLE:-default} | $VARIABLE  |       "default"       |       "default"       |
:= | ${VARIABLE:=default} | $VARIABLE  | $(VARIABLE="default") | $(VARIABLE="default") |
:? | ${VARIABLE:?default} | $VARIABLE  |       exit 127        |       exit 127        |
:+ | ${VARIABLE:+default} | "default"  |          ""           |          ""           |
   +----------------------+------------+-----------------------+-----------------------+

各グループ(前のコロンがある場合とない場合)のセットセット解除のケースは同じであるため、唯一の違いは空の方法です。ケースの処理方法です。

前のコロンでは、空のケースと未設定のケースは同じなので、可能な場合は使用します(つまり:==な場合は、空のケースに一貫性がないため、で)。

見出し:

  • セット平均VARIABLEは空ではない(VARIABLE="something"
  • 空の手段は、VARIABLE(空/ヌルですVARIABLE="")である
  • unsetVARIABLE存在しないことを意味します(unset VARIABLE

値:

  • $VARIABLE 結果は変数の元の値であることを意味します。
  • "default" 結果は提供された置換文字列でした。
  • "" 結果がnull(空の文字列)であることを意味します。
  • exit 127 スクリプトが終了コード127で実行を停止することを意味します。
  • $(VARIABLE="default")結果は変数の元の値であることを意味し、将来の使用のための変数に割り当てられて設けられた置換文字列。

1
実際のコーディングエラーであるエラーのみを修正しました(変数を操作するときの不要な間接参照のインスタンス)。ドルが説明の解釈に影響を与えるいくつかのケースを修正するために編集を行いました。ところで、すべてのシェル変数(配列を除く)は文字列変数です。数値として解釈できる文字列が含まれている可能性があります。文字列について話すと、メッセージを曇らせるだけです。引用は文字列とは何の関係もありません。エスケープの代替手段にすぎません。VARIABLE=""と書くことができますVARIABLE=。それでも、前者の方が読みやすいです。
Palec 2017年

テーブルのおかげでとても便利ですが、未設定または空の場合はスクリプトを終了させようとしています。しかし、私が取得終了コードは、1ない127
宇宙飛行士

64

変数が空でないかどうかを確認するには、

if [[ $var ]]; then ...       # `$var' expands to a nonempty string

逆の場合は、変数が設定されていないか空であるかをテストします。

if [[ ! $var ]]; then ...     # `$var' expands to the empty string (set or not)

変数が設定されているかどうか(空か空でないか)を確認するには、

if [[ ${var+x} ]]; then ...   # `var' exists (empty or nonempty)
if [[ ${1+x} ]]; then ...     # Parameter 1 exists (empty or nonempty)

逆の場合、変数が設定されていないかどうかをテストします。

if [[ ! ${var+x} ]]; then ... # `var' is not set at all
if [[ ! ${1+x} ]]; then ...   # We were called with no arguments

私もこれをしばらく使用しています。削減された方法で:[ $isMac ] && param="--enable-shared"

@Bhaskar私はので、それはだと思う。この答えはすでに基本的に同じ答え(利用提供${variable+x}を取得するx場合に限っては$variableほぼ半分前年に設定されています)。また、なぜそれが正しいのかを説明する詳細な説明もあります。
Mark Haferkamp、2018

しかし、${variable+x}読み
づらい

35

最近のバージョンのBash(4.2以降かと思います。よくわかりません)では、次のようにします。

if [ ! -v SOMEVARIABLE ] #note the lack of a $ sigil
then
    echo "Variable is unset"
elif [ -z "$SOMEVARIABLE" ]
then
    echo "Variable is set to an empty string"
else
    echo "Variable is set to some string"
fi

5
また[ -v "$VARNAME" ]、これは誤りではなく、単に別のテストを実行することに注意してください。と仮定しVARNAME=fooます。次に、という名前の変数fooが設定されているかどうかを確認します。
chepner 2014年

5
移植性を求めている方への注意、-vPOSIXに準拠していません
kzh

入手した場合[: -v: unexpected operator、のbash代わりに使用することを確認する必要がありshます。
koppor

25
if [ "$1" != "" ]; then
  echo \$1 is set
else
  echo \$1 is not set
fi

引数については、私の意見では通常、引数の数である$#をテストするのが最善です。

if [ $# -gt 0 ]; then
  echo \$1 is set
else
  echo \$1 is not set
fi

1
最初のテストは逆方向です。私はあなたが望んでいると思います[ "$1" != "" ](または[ -n "$1" ])...
Gordon Davisson 2010

10
$1が空の文字列に設定されている場合、これは失敗します。
HelloGoodbye 2013年

2
回答の2番目の部分(カウントパラメータ)は$1、空の文字列に設定されている場合に、回答の最初の部分が機能しない場合に役立つ回避策です。
Mark Berry

set -o nounsetがオンの場合、これは失敗します。
Flimm

21

注意

bashタグがあるので、バッシュに重点を置いた答えを出しています。

簡潔な答え

Bashで名前付き変数のみを処理している限り、この関数は、たとえそれが空の配列であっても、変数が設定されているかどうかを常に通知するはずです。

variable-is-set() {
    declare -p "$1" &>/dev/null
}

なぜこれが機能するのか

Bash(少なくとも3.0まで)では、varが宣言/設定された変数であるdeclare -p var場合、declare変数varを現在のタイプと値に設定し、ステータスコード0(成功)を返すコマンドを出力します。varが宣言されていない場合はdeclare -p var、にエラーメッセージを出力し、stderrステータスコードを返します1。を使用して&>/dev/null、通常stdoutstderr出力の両方を/dev/null、表示されることはなく、ステータスコードは変更されません。したがって、関数はステータスコードのみを返します。

Bashで他のメソッドが(ときどき)失敗する理由

  • [ -n "$var" ]これは、${var[0]}が空でないかどうかのみをチェックします。(Bashでは$var、と同じ${var[0]}です。)
  • [ -n "${var+x}" ]これは、${var[0]}が設定されているかどうかのみをチェックします。
  • [ "${#var[@]}" != 0 ]これは、少なくとも1つのインデックス$varが設定されているかどうかをチェックするだけです。

このメソッドがBashで失敗した場合

これは(を含むという名前の変数のために働く$_)、いない特定の特殊変数($!$@$#$$$*$?$-$0$1$2、...、および任意の私が忘れてしまっている場合があります)。これらはいずれも配列ではないため、POSIXスタイル[ -n "${var+x}" ]はこれらの特殊変数のすべてに対して機能します。ただし、関数が呼び出されると、多くの特殊変数が値/存在を変更するため、関数でのラップには注意してください。

シェル互換性ノート

スクリプトに配列があり、できるだけ多くのシェルと互換性を持たせる場合は、typeset -pではなくを使用することを検討してくださいdeclare -p。kshは前者のみをサポートすることを読みましたが、これをテストすることはできませんでした。Bash 3.0+とZsh 5.5.1はどちらもとの両方typeset -pをサポートしていることは知っていdeclare -pます。ただし、これら2つのキーワード以外の違いについてはテストしていません。また、他のシェルについてもテストしていません。

スクリプトをPOSIX sh互換にする必要がある場合は、配列を使用できません。配列なしで[ -n "{$var+x}" ]動作します。

Bashのさまざまなメソッドの比較コード

この関数はvar、variableの設定を解除しeval、渡されたコードをsし、テストを実行varして、evaldコードによって設定されているかどうかを判断し、最終的に、さまざまなテストの結果のステータスコードを表示します。

私はスキップだtest -v var[ -v var ][[ -v var ]]彼らはPOSIX標準に同じ結果が得られるので[ -n "${var+x}" ]、バッシュ4.2 +を必要としています。私がテストしたシェル(Bash 3.0から5.0、およびZsh 5.5.1)とtypeset -p同じなのでスキップしdeclare -pます。

is-var-set-after() {
    # Set var by passed expression.
    unset var
    eval "$1"

    # Run the tests, in increasing order of accuracy.
    [ -n "$var" ] # (index 0 of) var is nonempty
    nonempty=$?
    [ -n "${var+x}" ] # (index 0 of) var is set, maybe empty
    plus=$?
    [ "${#var[@]}" != 0 ] # var has at least one index set, maybe empty
    count=$?
    declare -p var &>/dev/null # var has been declared (any type)
    declared=$?

    # Show test results.
    printf '%30s: %2s %2s %2s %2s\n' "$1" $nonempty $plus $count $declared
}

テストケースコード

変数が連想配列として宣言されていない場合、Bashは非数値配列インデックスを「0」として扱うため、テスト結果は予期しないものになる可能性があることに注意してください。また、連想配列はBash 4.0以降でのみ有効です。

# Header.
printf '%30s: %2s %2s %2s %2s\n' "test" '-n' '+x' '#@' '-p'
# First 5 tests: Equivalent to setting 'var=foo' because index 0 of an
# indexed array is also the nonindexed value, and non-numerical
# indices in an array not declared as associative are the same as
# index 0.
is-var-set-after "var=foo"                        #  0  0  0  0
is-var-set-after "var=(foo)"                      #  0  0  0  0
is-var-set-after "var=([0]=foo)"                  #  0  0  0  0
is-var-set-after "var=([x]=foo)"                  #  0  0  0  0
is-var-set-after "var=([y]=bar [x]=foo)"          #  0  0  0  0
# '[ -n "$var" ]' fails when var is empty.
is-var-set-after "var=''"                         #  1  0  0  0
is-var-set-after "var=([0]='')"                   #  1  0  0  0
# Indices other than 0 are not detected by '[ -n "$var" ]' or by
# '[ -n "${var+x}" ]'.
is-var-set-after "var=([1]='')"                   #  1  1  0  0
is-var-set-after "var=([1]=foo)"                  #  1  1  0  0
is-var-set-after "declare -A var; var=([x]=foo)"  #  1  1  0  0
# Empty arrays are only detected by 'declare -p'.
is-var-set-after "var=()"                         #  1  1  1  0
is-var-set-after "declare -a var"                 #  1  1  1  0
is-var-set-after "declare -A var"                 #  1  1  1  0
# If 'var' is unset, then it even fails the 'declare -p var' test.
is-var-set-after "unset var"                      #  1  1  1  1

テスト出力

ヘッダ行対応のテストニーモニックに[ -n "$var" ][ -n "${var+x}" ][ "${#var[@]}" != 0 ]、およびdeclare -p var、それぞれ。

                         test: -n +x #@ -p
                      var=foo:  0  0  0  0
                    var=(foo):  0  0  0  0
                var=([0]=foo):  0  0  0  0
                var=([x]=foo):  0  0  0  0
        var=([y]=bar [x]=foo):  0  0  0  0
                       var='':  1  0  0  0
                 var=([0]=''):  1  0  0  0
                 var=([1]=''):  1  1  0  0
                var=([1]=foo):  1  1  0  0
declare -A var; var=([x]=foo):  1  1  0  0
                       var=():  1  1  1  0
               declare -a var:  1  1  1  0
               declare -A var:  1  1  1  0
                    unset var:  1  1  1  1

概要

  • declare -p var &>/dev/null (100%?)3.0以降のBashで名前付き変数をテストするための信頼性があります。
  • [ -n "${var+x}" ] POSIX準拠の状況では信頼できますが、配列を処理できません。
  • 変数が空でないかどうかをチェックするため、および他のシェルで宣言された変数をチェックするための他のテストが存在します。ただし、これらのテストは、BashスクリプトとPOSIXスクリプトのどちらにも適していません。

3
私が試した答えの中で、これ(declare -p var &>/dev/null)が機能する唯一のものです。ありがとうございました!
user1387866

2
@ mark-haferkamp私はあなたの答えを編集して重要な前の「/」を関数コードに追加して読み取った... &> /dev/nullが、SOは単一の文字の編集を許可しなかった🙄(> 6文字でなければならない-空白を追加しようとしてもしかし、それはうまくいきませんでした)。また、あなたが指摘したように、などの特別な変数はここでは機能しないので$1、サンプルの名前付き変数(たとえばOUTPUT_DIR)に切り替えるように関数を変更する価値があるかもしれ$1ません。とにかく、それは重要な編集です。それ以外の場合、コードはnullという相対ディレクトリにというファイルを作成しようとしていますdev。ところで-素晴らしい答えです!
-joehanna

また、$接頭辞なしで変数名を使用しても機能しdeclare -p PATH &> /dev/nullます。0をdeclare -p ASDFASDGFASKDF &> /dev/null返し、as は1 を返します(bash 5.0.11(1)-releaseの場合)
joehanna

1
すごい仕事!警告の1単語:declare var変数を変数として宣言しますが、次のように設定しませset -o nounsetdeclare foo bar=; set -o nounset; echo $bar; echo $foo
xebecheで

@joehannaその行方不明をキャッチしてくれてありがとう/!私はそれを修正しましたが、特に@xebecheのコメントに照らして、ロジックは機能を保証するのに十分に混乱していると思います。@xebecheこれは私の答えには不便です。… declare -p "$1" | grep =またはのようなものを試さなければならないようtest -v "$1"です。
Mark Haferkamp

19

スクリプトで次のように設定されている場合に、 未設定または空かどうかを確認しようとしている人のためにset -u

if [ -z "${var-}" ]; then
   echo "Must provide var environment variable. Exiting...."
   exit 1
fi

定期的な[ -z "$var" ]チェックはして失敗するvar; unbound variable場合set -uが、[ -z "${var-}" ] 拡大する場合は、空の文字列にvar失敗することなく設定されていません。


コロンがありません。それはそう${var:-}であるべきではありません${var-}。しかし、Bashでは、コロンがなくても機能することを確認できます。
Palec、2016年

3
${var:-}そして、${var-}異なるものを意味します。${var:-}場合は、空の文字列に展開されますvar未設定またはヌル${var-}のみ未設定の場合、文字列を空に拡大していきます。
RubenLaguna

何か新しいことを学びました、ありがとう!コロンを省略すると、設定されていないパラメーターのみがテストされます。言い換えると、コロンが含まれている場合、演算子は両方のパラメーターの存在と、その値がnullではないことをテストします。コロンが省略されている場合、オペレーターは存在のみをテストします。ここでは違いはありませんが、知っておくと役に立ちます。
Palec 2016年

17

設定されていない場合は終了します

これでうまくいきました。パラメータが設定されていない場合、スクリプトにエラーメッセージを表示して終了させたいと思いました。

#!/usr/bin/env bash

set -o errexit

# Get the value and empty validation check all in one
VER="${1:?You must pass a version of the format 0.0.0 as the only argument}"

実行するとエラーが返されます

peek@peek:~$ ./setver.sh
./setver.sh: line 13: 1: You must pass a version of the format 0.0.0 as the only argument

チェックのみ、出口なし-空および未設定は無効です

値がset = VALIDまたはunset / empty = INVALIDかどうかを確認するだけの場合は、このオプションを試してください。

TSET="good val"
TEMPTY=""
unset TUNSET

if [ "${TSET:-}" ]; then echo "VALID"; else echo "INVALID";fi
# VALID
if [ "${TEMPTY:-}" ]; then echo "VALID"; else echo "INVALID";fi
# INVALID
if [ "${TUNSET:-}" ]; then echo "VALID"; else echo "INVALID";fi
# INVALID

または、短いテストでも;-)

[ "${TSET:-}"   ] && echo "VALID" || echo "INVALID"
[ "${TEMPTY:-}" ] && echo "VALID" || echo "INVALID"
[ "${TUNSET:-}" ] && echo "VALID" || echo "INVALID"

チェックのみ、出口なし-空のみは無効です

そして、これが質問への答えです。値がset / empty = VALIDまたはunset = INVALIDかどうかを確認するだけの場合は、これを使用します。

注、「..- 1}」の「1」は重要ではなく、何でもかまいません(xなど)

TSET="good val"
TEMPTY=""
unset TUNSET

if [ "${TSET+1}" ]; then echo "VALID"; else echo "INVALID";fi
# VALID
if [ "${TEMPTY+1}" ]; then echo "VALID"; else echo "INVALID";fi
# VALID
if [ "${TUNSET+1}" ]; then echo "VALID"; else echo "INVALID";fi
# INVALID

短いテスト

[ "${TSET+1}"   ] && echo "VALID" || echo "INVALID"
[ "${TEMPTY+1}" ] && echo "VALID" || echo "INVALID"
[ "${TUNSET+1}" ] && echo "VALID" || echo "INVALID"

この回答は、質問に正確に回答するように要求した@ mklement0(コメント)に捧げます。

リファレンスhttp://pubs.opengroup.org/onlinepubs/9699919799/utilities/V3_chap02.html#tag_18_06_02


15

変数に空でない値が設定されているかどうかを確認するに[ -n "$x" ]は、他のユーザーがすでに示しているように、を使用します。

ほとんどの場合、値が空の変数は、設定されていない変数と同じように扱うことをお勧めします。:あなたがする必要がある場合しかし、あなたは2を区別することができます[ -n "${x+set}" ]"${x+set}"に展開されsetている場合x場合は、空の文字列に設定され、にx設定されていません)。

パラメータが渡されたかどうかを確認するには$#、関数(または関数ではない場合はスクリプト)に渡されるパラメータの数をテストします(Paulの回答を参照)。


14

bashマニュアルページの「パラメータ拡張」セクションを読んでください。パラメーターの展開では、設定される変数の一般的なテストは行われませんが、パラメーターが設定されていない場合、パラメーターに対して実行できることがいくつかあります。

例えば:

function a {
    first_arg=${1-foo}
    # rest of the function
}

割り当てられfirst_argている$1場合はに設定され、それ以外の場合は値「foo」が使用されます。場合はa、絶対に、単一のパラメータを取り、何も良いデフォルトが存在してはならないパラメータが与えられていないとき、あなたはエラーメッセージを出して終了することができます:

function a {
    : ${1?a must take a single argument}
    # rest of the function
}

:引数の値を展開するだけのnullコマンドとしての使用に注意してください。$1この例では何もしたくないので、設定されていない場合は終了します)


1
他のどの回答もシンプルでエレガントなものについて言及していないことに私は困惑してい: ${var?message}ます。
Tripleee、2015

どこからこれを取ったの?素晴らしい!ジャスタはうまくいきます!そして、それは短くてエレガントです!ありがとうございました!
ロジャー

13

bash -vでは[[ ]]組み込みの内部で使用できます:

#! /bin/bash -u

if [[ ! -v SOMEVAR ]]; then
    SOMEVAR='hello'
fi

echo $SOMEVAR

8

を使用すること[[ -z "$var" ]]は、変数が設定されているかどうかを確認する最も簡単な方法ですが、そのオプション-zは、未設定の変数と空の文字列に設定された変数を区別しません。

$ set=''
$ [[ -z "$set" ]] && echo "Set" || echo "Unset" 
Unset
$ [[ -z "$unset" ]] && echo "Set" || echo "Unset"
Unset

変数のタイプ(env変数、パラメーター、または通常の変数)に従ってチェックすることをお勧めします。

環境変数の場合:

[[ $(env | grep "varname=" | wc -l) -eq 1 ]] && echo "Set" || echo "Unset"

パラメータの場合(たとえば、パラメータの存在を確認するには$5):

[[ $# -ge 5 ]] && echo "Set" || echo "Unset"

通常の変数の場合(補助関数を使用して、エレガントな方法で実行するには):

function declare_var {
   declare -p "$1" &> /dev/null
}
declare_var "var_name" && echo "Set" || echo "Unset"

ノート:

  • $#位置パラメータの数を示します。
  • declare -pパラメータとして渡される変数の定義を提供します。存在する場合は0を返し、存在しない場合は1を返し、エラーメッセージを出力します。
  • &> /dev/nulldeclare -p戻りコードに影響を与えずにからの出力を抑制します。

5

上記の回答set -uは、Bashオプションが有効になっている場合は機能しません。また、それらは動的ではありません。たとえば、「ダミー」という名前の変数が定義されているかどうかをテストする方法は定義されていますか?これを試して:

is_var_defined()
{
    if [ $# -ne 1 ]
    then
        echo "Expected exactly one argument: variable name as string, e.g., 'my_var'"
        exit 1
    fi
    # Tricky.  Since Bash option 'set -u' may be enabled, we cannot directly test if a variable
    # is defined with this construct: [ ! -z "$var" ].  Instead, we must use default value
    # substitution with this construct: [ ! -z "${var:-}" ].  Normally, a default value follows the
    # operator ':-', but here we leave it blank for empty (null) string.  Finally, we need to
    # substitute the text from $1 as 'var'.  This is not allowed directly in Bash with this
    # construct: [ ! -z "${$1:-}" ].  We need to use indirection with eval operator.
    # Example: $1="var"
    # Expansion for eval operator: "[ ! -z \${$1:-} ]" -> "[ ! -z \${var:-} ]"
    # Code  execute: [ ! -z ${var:-} ]
    eval "[ ! -z \${$1:-} ]"
    return $?  # Pedantic.
}

関連:Bashでは、変数が「-u」モードで定義されているかどうかをどのようにテストしますか


1
なぜこの回答が反対票を投じられたのかを知りたいのですが...
LavaScornedOven 2014

Bashでは、evalなしで同じことを行うことができます:eval "[ ! -z \${$1:-} ]"間接評価に変更:[ ! -z ${!1:-} ];

@BinaryZebra:面白いアイデア。別の回答として投稿することをお勧めします。
kevinarpe 2015年

「eval」を使用すると、このソリューションはコードインジェクションに対して脆弱になります。$ is_var_defined 'x}]; echo "gotcha">&2; # 'gotcha
鉄人

4

できるよ:

function a {
        if [ ! -z "$1" ]; then
                echo '$1 is set'
        fi
}

9
または、あなたはそうすることができ-n、否定しないでください-z
追って通知があるまで一時停止。

1
$1つまり、引用符が必要です[ ! -z "$1" ]。または[[ ! -z $1 ]]、bash / ksh / zshに書き込むこともできます。
Gilles「SO-邪悪になるのをやめる」

5
$1が空の文字列に設定されている場合、これは失敗します。
HelloGoodbye 2013年

4

私の好ましい方法はこれです:

$ var=10
$ if ! ${var+false};then echo "is set";else echo "NOT set";fi
is set
$ unset -v var
$ if ! ${var+false};then echo "is set";else echo "NOT set";fi
NOT set

したがって、基本的に、変数が設定されている場合、それは「結果の否定false」になります(何がtrue=「設定される」)。

また、設定されていない場合は、「結果の否定true」になります(空の結果はに評価されるためtrue)(つまり、false「=設定されていません」として終了します)。



1

シェル-zでは、stringの長さがゼロの場合にTrueになる演算子を使用できます。

設定されていMY_VARない場合にデフォルトを設定する単純なワンライナー。それ以外の場合はオプションでメッセージを表示できます。

[[ -z "$MY_VAR" ]] && MY_VAR="default"
[[ -z "$MY_VAR" ]] && MY_VAR="default" || echo "Variable already set."

0
if [[ ${1:+isset} ]]
then echo "It was set and not null." >&2
else echo "It was not set or it was null." >&2
fi

if [[ ${1+isset} ]]
then echo "It was set but might be null." >&2
else echo "It was was not set." >&2
fi

$1$2および最大$Nが常に設定されます。これは失敗です。

私は試してみましたが、うまくいきませんでした。おそらく私のbashバージョンは、それをサポートしていません。Idk、ごめんなさい。:)

0

で何かを確認したい場合は、これを行うための(はるかに)優れたコードを見つけました$@

if [[$ 1 = ""]]
その後
  エコー '$ 1 is blank'
そうしないと
  エコー '$ 1がいっぱいです'
fi

なぜこれがすべてなのか のすべて$@がBash に存在しますが、デフォルトでは空白になっているためtest -ztest -n役に立ちませんでした。

更新:パラメータの文字数を数えることもできます。

[$ {#1} = 0の場合]
その後
  エコー '$ 1 is blank'
そうしないと
  エコー '$ 1がいっぱいです'
fi

私は知っていますが、それだけです。何かが空の場合、エラーが発生します!ごめんなさい。:P

0
if [[ ${!xx[@]} ]] ; then echo xx is defined; fi

11
StackOverflowへようこそ。あなたの答えは高く評価されていますが、コードだけでなくそれ以上のものを与えるのが最善です。回答に理由を付けたり、簡単な説明を加えたりできますか?回答を拡大するための他のアイデアについては、このページを参照してください。
セレオ2015

0

これは私が毎日使うものです:

#
# Check if a variable is set
#   param1  name of the variable
#
function is_set()
{
    [[ -n "${1}" ]] && test -n "$(eval "echo "\${${1}+x}"")"
}

これは、bash 3.0までのLinuxおよびSolarisでうまく機能します。

bash-3.00$ myvar="TEST"
bash-3.00$ is_set myvar ; echo $?
0
bash-3.00$ mavar=""
bash-3.00$ is_set myvar ; echo $?
0
bash-3.00$ unset myvar
bash-3.00$ is_set myvar ; echo $?
1

1
Bash 2.0以降間接拡張が利用可能です。あなたはtest -n "$(eval "echo "\${${1}+x}"")"同等のもののために長いと複雑な(evalも含まれている)を置き換えることができます:[[ ${!1+x} ]]

0

私はbashの大まかな詳細を隠す補助関数が好きです。この場合、そうすることでさらに(隠された)粗さが追加されます。

# The first ! negates the result (can't use -n to achieve this)
# the second ! expands the content of varname (can't do ${$varname})
function IsDeclared_Tricky
{
  local varname="$1"
  ! [ -z ${!varname+x} ]
}

私はこの実装に最初にバグがあったため(イェンスとライオネルの回答に触発されて)、別の解決策を考え出しました。

# Ask for the properties of the variable - fails if not declared
function IsDeclared()
{
  declare -p $1 &>/dev/null
}

私はそれがより簡単で、よりずんぐりしていて、理解/覚えやすいと思う。テストケースはそれが同等であることを示しています:

function main()
{
  declare -i xyz
  local foo
  local bar=
  local baz=''

  IsDeclared_Tricky xyz; echo "IsDeclared_Tricky xyz: $?"
  IsDeclared_Tricky foo; echo "IsDeclared_Tricky foo: $?"
  IsDeclared_Tricky bar; echo "IsDeclared_Tricky bar: $?"
  IsDeclared_Tricky baz; echo "IsDeclared_Tricky baz: $?"

  IsDeclared xyz; echo "IsDeclared xyz: $?"
  IsDeclared foo; echo "IsDeclared foo: $?"
  IsDeclared bar; echo "IsDeclared bar: $?"
  IsDeclared baz; echo "IsDeclared baz: $?"
}

main

テストケースは、varを宣言local varないことも示しています(「=」が後に続かない限り)。かなり長い間、この方法で変数を宣言したと思っていましたが、今は自分の意図を単に表現しているだけであることに気づきました...それは何もしません。

IsDeclared_Tricky xyz:1
IsDeclared_Tricky foo:1
IsDeclared_Tricky bar:0
IsDeclared_Tricky baz:0
IsDeclared xyz:1
IsDeclared foo:1
IsDeclared bar:0
IsDeclared baz:0

ボーナス:ユースケース

私は主にこのテストを使用して、やや「優雅」で安全な方法で(ほとんどインターフェースに似ています...)関数にパラメーターを提供(および返す)します。

#auxiliary functions
function die()
{
  echo "Error: $1"; exit 1
}

function assertVariableDeclared()
{
  IsDeclared "$1" || die "variable not declared: $1"
}

function expectVariables()
{
  while (( $# > 0 )); do
    assertVariableDeclared $1; shift
  done
}

# actual example
function exampleFunction()
{
  expectVariables inputStr outputStr
  outputStr="$inputStr world!"
}

function bonus()
{
  local inputStr='Hello'
  local outputStr= # remove this to trigger error
  exampleFunction
  echo $outputStr
}

bonus

すべてで呼び出された場合、宣言された変数が必要です。

こんにちは世界!

そうしないと:

エラー:変数が宣言されていません:outputStr


0

すべての答えをすくい取った後、これも機能します:

if [[ -z $SOME_VAR ]]; then read -p "Enter a value for SOME_VAR: " SOME_VAR; fi
echo "SOME_VAR=$SOME_VAR"

SOME_VAR私が持っているものの代わりにあなたが入れなければ$SOME_VAR、それはそれを空の値に設定します。$これが機能するために必要です。


エラーが表示set -uされる場合は機能しませんunboud variable
Michael Heuberger '30

0

概要

  • test -n "${var-}"変数が空でないかどうかを確認するために使用します(したがって、定義/設定も必要です)
  • test ! -z "${var+}"変数が定義または設定されているかどうかを確認するために使用します(空であっても)

シェルスクリプトでは最初の使用例がはるかに一般的であり、これが通常使用するものです。

ノート

  • このソリューションは、すべてのPOSIXシェル(sh、bash、zsh、ksh、dash)で機能するはずです。
  • この質問に対する他の回答の一部は正しいですが、シェルスクリプトの経験が浅い人には混乱する可能性があるため、そのような人にとっては最も混乱の少ないTLDR回答を提供したいと思いました。

説明

このソリューションがどのように機能するかを理解するには、POSIX testコマンドとPOSIXシェルパラメータ展開(spec)を理解する必要があります。そのため、答えを理解するために必要な絶対的な基礎をカバーしましょう。

testコマンドは式を評価し、(終了ステータスを介して)trueまたはfalseを返します。-nオペランドが空でない文字列の場合、演算子はtrueを返します。したがって、たとえば、test -n "a"trueをtest -n ""返し、false を返します。これで、変数が空ではない(つまり、定義する必要がある)かどうかを確認するには、を使用できますtest -n "$var"。ただし、一部のシェルスクリプトにはオプションセット(set -u)があり、未定義の変数を参照するとエラーが発生するため、変数varが定義されていない場合、式$aによってエラーが発生します。このケースを正しく処理するには、変数拡張を使用する必要があります。これにより、変数が定義されていない場合は変数を代替文字列に置き換えるようにシェルに指示し、前述のエラーを回避します。

変数の展開と${var-}は、変数varが定義されていない場合(「unset」とも呼ばれる)、空の文字列に置き換えることです。したがって、test -n "${var-}"$var空でない場合はtrueを返します。これはほとんどの場合、シェルスクリプトでチェックしたいものです。逆のチェックは、$var未定義または空でない場合、になりますtest -z "${var-}"

次に、2番目の使用例として、変数varが定義されているかどうか、空かどうかを確認します。これはあまり一般的ではない使用例であり、少し複雑です。Lionelsのすばらしい回答を読んで理解を深めることをお勧めします。


-1

変数が設定されているかどうかを確認するには

var=""; [[ $var ]] && echo "set" || echo "not set"

3
$varが空の文字列に設定されている場合、これは失敗します。
HelloGoodbye 2013年

-1

変数がバインドされているかどうかをテストする場合は、nounsetオプションをオンにした後でも、これはうまく機能します。

set -o noun set

if printenv variableName >/dev/null; then
    # variable is bound to a value
else
    # variable is unbound
fi

私はあなたが意味すると思うset -o nounset、ではありませんset -o noun set。これはexport編集された変数に対してのみ機能します。また、元に戻すのが面倒な方法で設定が変更されます。
キーストンプソン
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.