文字列がBashシェルスクリプトで定義されていないかどうかを確認する方法


151

null文字列を確認したい場合は、

[ -z $mystr ]

しかし、変数が定義されているかどうかを確認したい場合はどうなりますか?または、Bashスクリプトに違いはありませんか?


27
[-z $ mystr]ではなく[-z "$ mystr"]を使用する癖をつけてください
Charles Duffy

逆のことをするには?文字列がnullでない場合に意味します
ウェイを開く

1
@flow:どうですか[ -n "${VAR+x}"] && echo not null
Lekensteyn 2011

1
@CharlesDuffyたくさんのオンラインリソースでこれを読んだことがあります。なぜこれが望ましいのですか?
誕生

6
@Ayos引用符がない場合、変数の内容は文字列分割され、グロブされるためです。空の文字列の場合はの[ -z ]代わりになり[ -z "" ]ます。スペースがある場合は、[ -z "my" "test" ]ではなくになり[ -z my test ]ます。の場合[ -z * ]*はディレクトリ内のファイルの名前に置き換えられます。
Charles Duffy

回答:


138

簡単に説明されていませんが、あなたの回答Vinko回答に含まれています(明記されていない場合)。VARが設定されているが空か設定されていないかを区別するには、以下を使用できます。

if [ -z "${VAR+xxx}" ]; then echo VAR is not set at all; fi
if [ -z "$VAR" ] && [ "${VAR+xxx}" = "xxx" ]; then echo VAR is set but empty; fi

おそらく、2行目の2つのテストを1つに組み合わせることができます。

if [ -z "$VAR" -a "${VAR+xxx}" = "xxx" ]; then echo VAR is set but empty; fi

ただし、Autoconfのドキュメントを読むと、用語を ' -a'と組み合わせることは推奨されておらず、と組み合わせた個別の簡単なテストを使用することが推奨されてい&&ます。問題のあるシステムには遭遇していません。これは、それらが以前は存在していなかったことを意味するわけではありません(ただし、遠い昔はそれほど珍しくなかったとしても、おそらく最近では非常にまれです)。

これらの詳細、およびその他の関連するシェルパラメーター展開testor[コマンド、条件式は、Bashのマニュアルに記載されています。


私は最近、この回答についてメールで質問されました:

あなたは2つのテストを使用し、私は2番目のテストをよく理解していますが、最初のテストは理解していません。より正確には、変数展開の必要性を理解していません

if [ -z "${VAR+xxx}" ]; then echo VAR is not set at all; fi

これは同じことを達成しないでしょうか?

if [ -z "${VAR}" ]; then echo VAR is not set at all; fi

公正な質問-答えは「いいえ、より簡単な代替案では同じことはできません」です。

あなたのテストの前にこれを書いたとしましょう:

VAR=

テストでは「VARは設定されていません」と表示されますが、私は(暗黙的に何もエコーしないため)、「VARは設定されていますが、値が空である可能性があります」と表示します。このスクリプトを試してください:

(
unset VAR
if [ -z "${VAR+xxx}" ]; then echo JL:1 VAR is not set at all; fi
if [ -z "${VAR}" ];     then echo MP:1 VAR is not set at all; fi
VAR=
if [ -z "${VAR+xxx}" ]; then echo JL:2 VAR is not set at all; fi
if [ -z "${VAR}" ];     then echo MP:2 VAR is not set at all; fi
)

出力は次のとおりです。

JL:1 VAR is not set at all
MP:1 VAR is not set at all
MP:2 VAR is not set at all

テストの2番目のペアでは、変数は設定されていますが、空の値に設定されています。これは、${VAR=value}および${VAR:=value}表記法による区別です。${VAR-value}and ${VAR:-value}、および${VAR+value}and などの同上${VAR:+value}


以下のようギリは、彼の中で指摘答え、あなたが実行した場合、bashset -o nounsetオプションは、上記の基本的な答えはで失敗しますunbound variable。簡単に修正できます:

if [ -z "${VAR+xxx}" ]; then echo VAR is not set at all; fi
if [ -z "${VAR-}" ] && [ "${VAR+xxx}" = "xxx" ]; then echo VAR is set but empty; fi

またはset -o nounsetset +uset -uと同等set -o nounset)でオプションをキャンセルできます。


7
この答えで私が持っている唯一の問題は、かなり間接的で不明確な方法でそのタスクを実行することです。
スイス

3
bashのマニュアルページで上記の意味の説明を確認したい場合は、「パラメータの展開」セクションを探し、次にこのテキストを探してください。「以下に記載されているフォームを使用して、部分文字列の展開を実行しない場合、bashのテスト未設定またはnullのパラメーター['null'は空の文字列を意味します]コロンを省略すると、未設定のパラメーターに対してのみテストが行​​われます(...)$ {parameter:+ word}:代替値を使用します。 nullまたは未設定の場合、何も置換されません。それ以外の場合は、単語の拡張が置換されます。」
David Tonhofer

2
@スイスこれは不明確でも間接でもありませんが、慣用的です。おそらく、とプログラマの不慣れに${+}し、${-}それは不明であるが、1は、シェルの有能なユーザーにする場合、それらの構造に精通して不可欠です。
William Pursell、

これを有効にして実装する場合は、stackoverflow.com / a / 20003892/14731を参照してくださいset -o nounset
ギリ2013年

私はこれについて多くのテストを行いました。スクリプトの結果に一貫性がないためです。私は[ -v VAR ]bash -s v4.2 以降での「」アプローチを検討することをお勧めします。
ます

38
~> if [ -z $FOO ]; then echo "EMPTY"; fi
EMPTY
~> FOO=""
~> if [ -z $FOO ]; then echo "EMPTY"; fi
EMPTY
~> FOO="a"
~> if [ -z $FOO ]; then echo "EMPTY"; fi
~> 

-zは未定義の変数に対しても機能します。未定義と定義済みを区別するには、ここにリストされているものを使用するか、またはより明確な説明とともに、ここを使用します

最もクリーンな方法は、これらの例のように拡張を使用することです。すべてのオプションを取得するには、マニュアルの「パラメーター拡張」セクションを確認してください。

代替単語:

~$ unset FOO
~$ if test ${FOO+defined}; then echo "DEFINED"; fi
~$ FOO=""
~$ if test ${FOO+defined}; then echo "DEFINED"; fi
DEFINED

デフォルト値:

~$ FOO=""
~$ if test "${FOO-default value}" ; then echo "UNDEFINED"; fi
~$ unset FOO
~$ if test "${FOO-default value}" ; then echo "UNDEFINED"; fi
UNDEFINED

もちろん、これらのいずれかを異なる方法で使用し、「デフォルト値」の代わりに必要な値を入力し、必要に応じて拡張を直接使用します。


1
しかし、文字列が ""であるか、これまで定義されていないかを区別したいと思います。それは可能ですか?
Setjmp 2008年

1
この答え、これら2つのケースを区別する方法を示してます。詳細については、bash faqリンクを参照してください。
チャールズダッフィー、

1
私はチャールズ、彼のコメントの後にそれを追加しました
Vinko Vrsalovic

2
これらすべての「トリック」については、bashのマニュアルページで「パラメータ拡張」を検索してください。たとえば、$ {foo:-default}はデフォルト値を使用し、$ {foo:= default}はデフォルト値を割り当てます。$ {foo:?error message}は、fooが設定されていない場合にエラーメッセージを表示します。など
Jouni K 。Seppänen

18

高度なbashスクリプトガイド、10.2 パラメータ置換:

  • $ {var + blahblah}:varが定義されている場合、式の代わりに「blahblah」が使用されます。それ以外の場合はnullが使用されます
  • $ {var-blahblah}:varが定義されている場合、それ自体が置換されます。それ以外の場合は、「blahblah」が置換されます
  • $ {var?blahblah}:varが定義されている場合、それが置換されます。それ以外の場合、エラーメッセージとして 'blahblah'を含む関数が存在します。


変数$ mystrが定義されているかどうかに基づいてプログラムロジックを作成するには、次のようにします。

isdefined=0
${mystr+ export isdefined=1}

isdefined = 0の場合、変数は未定義でした。isdefined= 1の場合、変数は定義されました。

変数をチェックするこの方法は、エレガントで読みやすく、未定義の変数の使用でエラーが発生するようにbashシェルが構成されていると(set -u)、スクリプトが途中で終了するため、上記の回答よりも優れています。


その他の便利なもの:

$ mystrに未定義の場合はデフォルト値の7を割り当て、それ以外の場合はそのままにします。

mystr=${mystr- 7}

変数が定義されていない場合にエラーメッセージを出力して関数を終了するには:

: ${mystr? not defined}

$ mystrの内容が定義されている場合にコマンドとして実行されないようにするため、ここでは「:」を使用していることに注意してください。


私は知りませんでしたか?BASH変数の構文。それはいいキャッチです。
スイス

これは、間接変数参照でも機能します。これはパスしvar= ; varname=var ; : ${!varname?not defined}、これは終了しますvarname=var ; : ${!varname?not defined}。しかしset -u、同じことをはるかに簡単に行うのは良い習慣です。
2013

11

テストの要約。

[ -n "$var" ] && echo "var is set and not empty"
[ -z "$var" ] && echo "var is unset or empty"
[ "${var+x}" = "x" ] && echo "var is set"  # may or may not be empty
[ -n "${var+x}" ] && echo "var is set"  # may or may not be empty
[ -z "${var+x}" ] && echo "var is unset"
[ -z "${var-x}" ] && echo "var is set and empty"

bashの良い習慣。ときどきファイルパスにスペースが含まれるか、コマンドインジェクションから保護されます
k107

1
${var+x}変数名にスペースを含めることが許可されている場合を除いて、それは必要ないと思います。
アンヴァンロッサム2015年

良い習慣だけではありません。だ必要[正しい結果を得るために。場合にvar設定されていないまたは空、[ -n $var ]に帰着[ -n ]終了ステータス0を有し、一方では、[ -n "$var" ]予想される(正しい)が1の終了ステータス
chepner

5

https://stackoverflow.com/a/9824943/14731には、より適切な回答が含まれています(より読みやすく、set -o nounset有効にすると機能します)。おおよそ次のように機能します。

if [ -n "${VAR-}" ]; then
    echo "VAR is set and is not empty"
elif [ "${VAR+DEFINED_BUT_EMPTY}" = "DEFINED_BUT_EMPTY" ]; then
    echo "VAR is set, but empty"
else
    echo "VAR is not set"
fi

4

定義されている変数を確認する明示的な方法は次のとおりです。

[ -v mystr ]

1
これは(bashまたはテスト用の)どのmanページでも見つかりませんが、私にとっては機能します。これが追加されたバージョンのアイデアはありますか?
Ash Berlin-Taylor

1
これは、セクションBourne Shell Builtinsの末尾の演算子から参照される、条件式に記載されています。いつ追加されたのかはわかりませんが、(3.2.51に基づく)のAppleバージョンにはないので、おそらく4.xの機能です。testbashbash
ジョナサンレフラー2013年

1
これは私にとってはうまくいきませんGNU bash, version 4.1.2(1)-release (x86_64-redhat-linux-gnu)。エラーは-bash: [: -v: unary operator expectedです。ここのコメントによると、それが動作するためには最低でもbash 4.2が必要です。
Acumenus 2014

それが利用可能になったときに確認していただきありがとうございます。以前はさまざまなシステムで使用していましたが、突然機能しなくなりました。私は好奇心からここに来ました。もちろん、このシステムのbashは3.x bashです。
2015

1

別のオプション:「リスト配列インデックス」拡張

$ unset foo
$ foo=
$ echo ${!foo[*]}
0
$ foo=bar
$ echo ${!foo[*]}
0
$ foo=(bar baz)
$ echo ${!foo[*]}
0 1

これが空の文字列に展開されるのfooはが設定されていない場合のみなので、条件付きの文字列で確認できます。

$ unset foo
$ [[ ${!foo[*]} ]]; echo $?
1
$ foo=
$ [[ ${!foo[*]} ]]; echo $?
0
$ foo=bar
$ [[ ${!foo[*]} ]]; echo $?
0
$ foo=(bar baz)
$ [[ ${!foo[*]} ]]; echo $?
0

3.0以上のbashバージョンで利用可能である必要があります


1

このバイクをさらに流すのではなく、追加したかった

shopt -s -o nounset

スクリプトの先頭に追加できるもので、変数がスクリプトのどこにも宣言されていない場合はエラーになります。表示されるメッセージはですunbound variableが、他の人が言うように、空の文字列やnull値をキャッチしません。個々の値が空でないことを確認するために、で展開された変数をテストでき${mystr:?}ますparameter null or not set。これは、でエラーになるドル記号展開とも呼ばれます。


1

Bashのリファレンスマニュアルは、 bashのに関する情報の信頼できるソースです。

次に、変数が存在するかどうかをテストする例を示します。

if [ -z "$PS1" ]; then
        echo This shell is not interactive
else
        echo This shell is interactive
fi

セクション6.3.2から。)

開いた後、[前の空白はオプションで]ないことに注意してください。


Vimユーザー向けのヒント

次のようにいくつかの宣言を持つスクリプトがありました。

export VARIABLE_NAME="$SOME_OTHER_VARIABLE/path-part"

しかし、私は彼らにあらゆる既存の価値を尊重してほしかった。だから私は彼らをこのように書くように書き直しました:

if [ -z "$VARIABLE_NAME" ]; then
        export VARIABLE_NAME="$SOME_OTHER_VARIABLE/path-part"
fi

これをvimで簡単な正規表現を使用して自動化することができました。

s/\vexport ([A-Z_]+)\=("[^"]+")\n/if [ -z "$\1" ]; then\r  export \1=\2\rfi\r/gc

これは、関連する行を視覚的に選択してから入力することで適用できます:。コマンドバーにはがあらかじめ入力されてい:'<,'>ます。上記のコマンドを貼り付けてEnterキーを押します。


このバージョンのVimでテスト済み:

VIM - Vi IMproved 7.3 (2010 Aug 15, compiled Aug 22 2015 15:38:58)
Compiled by root@apple.com

Windowsユーザーは、異なる行末が必要な場合があります。


0

変数が定義されているかどうかを確認するためのより明確な方法は次のとおりです。

var_defined() {
    local var_name=$1
    set | grep "^${var_name}=" 1>/dev/null
    return $?
}

次のように使用します。

if var_defined foo; then
    echo "foo is defined"
else
    echo "foo is not defined"
fi

1
関数を書くことは悪い考えではありません。呼び出しgrepはひどいです。で名前が指定されている変数の値を取得する方法としてがbashサポートさ${!var_name}れている$var_nameため、がname=value; value=1; echo ${name} ${!name}生成されることに注意してくださいvalue 1
ジョナサンレフラー2013年

0

未定義の変数をテストする短いバージョンは、次のようになります。

test -z ${mystr} && echo "mystr is not defined"

-3

引数なしで呼び出しセット...それが定義されているすべてのVARS ..出力
リストの最後のものは、あなたのスクリプト内で定義されたものだろう。..
あなたは物事が定義されているかを把握していただきましたができなかった何かにパイプ、その出力をできるように


2
私はこれに反対票を投じませんでしたが、かなり小さなナッツを割るのは大槌のようなものです。
ジョナサン・レフラー、

私は実際にこの答えが受け入れられた答えよりも好きです。この回答で何が行われているのかは明らかです。受け入れられた答えは地獄のように不安定です。
スイスの

この答えは、望ましいものというより、「セット」の実装の副作用のようです。
ジョナサンモーガン
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.