「if」ステートメントに変数が存在するかどうかを確認するにはどうすればよいですか?


69

ifステートメント内の変数の存在を確認する必要があります。効果のあるもの:

if [ -v $somevar ]
then
    echo "Variable somevar exists!"
else
    echo "Variable somevar does not exist!"

そして、それに最も近い質問はこれで、実際には私の質問に答えていません。


$somevar変数が存在しない場合に値/文字列に設定する場合:${somevar:=42}
サイラス

個人的には、空虚([ -n "$var" ]または[ ! -z "$var" ])だけをチェックする傾向があります。存在/非存在のチェックは微妙すぎると思うので、コードは粗くシンプルなほうが好きです。
PSkocik

なぜそれが必要なの[ -n "$var" ]ですか?関連:stackoverflow.com/questions/3601515/...
チロSantilli新疆改造中心法轮功六四事件

回答:


97

最新のbash(バージョン4.2以降):

[[ -v name_of_var ]]

からhelp test

-v VAR、シェル変数VARが設定されている場合はTrue


3
単一の角かっこでも機能します[ -v name_of_var ]
meuh

7
ハッシュと配列の場合、変数にkey / indice "0"の要素がない限りfalseを返すことに注意してください。namerefについては、ターゲットが定義されているかどうかをテストします。それはのような特別なパラメータのために動作しません$1$-$#...
ステファンChazelas

4
この機能は、bashビルトインtestまたは[; では利用できません/usr/bin/test。と比較man testしてくださいhelp test
マークラカタ

@MarkLakataそう、外部コマンドはシェルの内部状態を知ることができないからです。
クリスダウン

うーん、それは常に[[-v "$ name_of_var"]]であってはいけませんか?
アレクサンダーミルズ

24

存在するという意味に依存します。

宣言されているが割り当てられていない変数は存在しますか?

空のリストが割り当てられた配列(またはハッシュ)変数は存在しますか?

現在割り当てられていない変数を指すnameref変数は存在しますか?

あなたは検討してください$-$#$1変数?(POSIXはサポートしていません)。

Bourneのようなシェルでは、標準的な方法は次のとおりです。

if [ -n "${var+set}" ]; then
  echo '$var was set'
fi

これは、スカラー変数およびその他のパラメーターに対して機能し、変数に値が割り当てられているかどうかを判断します(空、そうでない、自動的に、環境、割り当て、readなどからfor)。

typesetor declareコマンドを持つシェルの場合、宣言ているが以外で割り当てられていない変数をsetとして報告しません。zsh

除いて、配列をサポートシェルのyashzshそれのように報告しないだろう indice 0の要素が設定されていない限り、配列変数。

連想配列タイプの変数の場合bash(ただし、そうではありませksh93zsh)、キー "0"の要素が設定されていない限り、変数は設定済みとして報告されません。

以下のためにksh93bash、型の変数のためのnameref namerefによって参照される変数を考慮そのものである場合にのみtrueを返すことを、セット

以下のためにkshzshそしてbash、潜在的により良いアプローチは次のようになります。

if ((${#var[@]})); then
  echo '$var (or the variable it references for namerefs) or any of its elements for array/hashes has been set'
fi

以下のためにksh93zshそしてbash4.4以上、またあります。

if typeset -p var 2> /dev/null | grep -q '^'; then
  echo '$var exists'
fi

設定または宣言された変数を報告します。


1
declare -p/もtypeset -p動作しbashます。
cas

1
@cas、いいえ。変数は宣言されていませんが、設定されていません。試してみてくださいbash -c 'typeset -i a; typeset -p a'とで比較しますksh93zsh
ステファンシャゼラス16年

+1ここに私を指摘してくれてありがとう。私の質問unix.stackexchange.com/q/280893/674
ティム

bash-4.4(2016年9月にリリース)で変更された@casを編集しました。
StéphaneChazelas 17年

9

SOに関する回答で述べたように、チェックする方法は次のとおりです。

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

ここで、$ {somevar + x}はパラメーター展開であり、varが設定されていない場合はnullに評価され、そうでない場合は文字列 "x"に置き換えられます。

を使用-nすると、他の回答で示唆されているように、変数に空の文字列が含まれているかどうかのみがチェックされます。存在を確認しません。


2
$somevarを処理するには引用する必要がありますIFS=x。それまたは引用のいずれかx
mikeserv

1
@mikeservありがとう、私はエッジケースについて学ぶのが好きif [ -z "${somevar+x}" ]です:) 引用は、まだ内部の必要とされるであろう[[]]
トム・ヘイル

@TomHale-はい、まれにあります。[ testテストの呼び出しでレンダリングするために依存する必要があり、通常の方法で注文したように、コマンドラインパラメータ、およびその通常の拡張や解釈を受け入れるルーチンを使用すると、任意のプログラムのコマンドラインで、それによって読み取ることが原因とすべきものを適用します。テスト{!+ "!"}
mikeserv

@mikeserv私の2番目の質問はあなたのイエスですか?最初の質問もイエスですか?
トム・ヘイル

1
+1; これset -uは、Bashのバージョンが4.2より前で、有効な場合にこれを行う最も簡単な方法のようです。
カイルストランド

4

POSIXly:

! (: "${somevar?}") 2>/dev/null && echo somevar unset

または、シェルにメッセージを表示させることができます:

(: "${somevar?}")
zsh: somevar: parameter not set

@mikeserv:ええ、もちろん、それを行う方法はたくさんあります。まず、これでこれを複製すると思います。しかし、この質問では、OPはチェックのみを行い、変数が設定されていない場合に終了または報告することを主張しなかったため、サブシェルでチェックを行いました。
cuonglm

2
まあ、私は知っていますが、それはあなたがそれをここでテストするための最良の方法ではないかもしれないことを示すようなサブシェルでそれをしなければならないからです-それは失敗時の停止アクションです失敗。移植可能であればtrap、EXITでのみ機能します。私が言っているのはこれだけです-合格/不合格としてはあまり当てはまりません。そして、これは私も話しているわけではありません-私はこれを正確に前にやったことがあり、私を説得するためにこのような小さなコメントチャットが必要でした。だから、私はそれを前倒しで支払うと思った。
mikeserv

1
@mikeserv:まあ、まあ、それは良い点です。私はただ、OPを構文と混同させる可能性があることを追加するのですか?)
cuonglm

2
if set|grep '^somevar=' >/dev/null;then
    echo "somevar exists"
else
    echo "does not exist"
fi

これはやや非効率的だとsh思いますが、非常にシンプルで互換性があり、まさに必要なものです。
ホイジュイ

2
printf ${var+'$var exists!\n'}

...印刷されない場合は何も印刷されません。または...

printf $"var does%${var+.}s exist%c\n" \ not !

...いずれかの方法で説明します。

テストの戻り値を使用して、条件に適した形式文字列に動的に展開できます。

[ "${var+1}" ]
printf $"var does%.$?0s exist%c\n" \ not !

またprintf、置換に基づいて失敗することができます...

printf $"var does%${var+.}s exist%c\n%.${var+b}d" \
        \ not ! \\c >&"$((2${var+-1}))" 2>/dev/null

...これは$var does not exist!、stderrに出力され、$var設定されていない場合は0以外$var does exist!を返します$varが、設定されている場合はstdoutに出力され、0を返します。


1

この単純な行は動作します(そしてほとんどのPOSIXシェルで動作します):

${var+"false"} && echo "var is unset"

または、より長い形式で書かれた:

unset var

if ${var+"false"}
then
   echo "var is unset"
fi

拡張は次のとおりです。

  • 変数に値がある場合(nullでも)、falseが置き換えられます
  • varに「値なし」がある場合、「値なし」(null)が置き換えられます。

${var+"false"}拡張は、「偽」の「ヌル」のどちらかに展開されます。
次に、「nothing」または「false」が実行され、終了コードが設定されます。

終了値は展開自体(の実行)によって設定されるため、コマンドtest[または[[)を呼び出す必要はありません。


はい、$IFSf、a、l、s、またはeを含むshエミュレーションのzshの一部の古いバージョンを除きます。他の答えと同様に、配列、ハッシュ、または言及したい他のタイプの変数の場合があります。
ステファンシャゼル

@StéphaneChazelas私が書いたmost POSIX shellsmost In the greatest number of instances、すべてでありません。... ...それで、はい、あいまいな状態when $IFS contains f, a, l, s or eで、一部のあいまいなシェルでは、some old versions of zshこれは失敗します。そのようなバグはずっと前に解決されていると思います。... ...ずっと前に壊れたシェル用のコードを書かなければならないことを提案していますか?

@StéphaneChazelasまた:質問のタイトルは非常に具体的です:Bash。

バイナリゼブラ???
mikeserv

0

純粋なシェルの方法:

[ "${var+1}" ] || echo "The variable has not been set"

テストスクリプト:

#!/bin/sh
echo "Test 1, var has not yet been created"
[ "${var+1}" ] || echo "The variable has not been set"

echo "Test 2, var=1"
var=1
[ "${var+1}" ] || echo "The variable has not been set"

echo "Test 3, var="
var=
[ "${var+1}" ] || echo "The variable has not been set"

echo "Test 4, unset var"
unset var
[ "${var+1}" ] || echo "The variable has not been set"
echo "Done"

結果:

Test 1, var has not yet been created
The variable has not been set
Test 2, var=1
Test 3, var=
Test 4, unset var
The variable has not been set
Done

1
変数がヌル文字列に設定されていると失敗します。
トム・ヘイル

0

bash 4.4.19では、次のことがうまくいきました。完全な例はこちら

$export MAGENTO_DB_HOST="anyvalue"

#!/bin/bash

if [ -z "$MAGENTO_DB_HOST" ]; then
    echo "Magento variable not set"
else
    echo $MAGENTO_DB_HOST
fi

-1

ifコマンドを使用してbashで宣言された変数の存在を確認することはできません-vが、新しいbashにはオプションがありますが、移植性がなく、古いbashバージョンでは使用できません。変数が存在しない場合、それを使用しているときに同時に生成されるためです。

たとえば、MYTEST変数を使用したり変数に値を割り当てたりしなかったが、echoコマンドを使用しているときは何も表示されないことを想像してください。または、使用しif [ -z $MYTEST ]ている場合はゼロ値を返しました!別の終了ステータスを返さなかったため、この変数は存在しないことがわかります。

これで2つのソリューションがあり-vます(オプションなし):

  1. declareコマンドを使用します。
  2. setコマンドを使用します。

例えば:

MYTEST=2
set | grep MYTEST
declare | grep MYTEST

しかし、残念なことに、これらのコマンドはメモリに関数をロードしたことを示しています!declare -p | grep -q MYTEST ; echo $?よりクリーンな結果を得るためにコマンドを使用できます。


-1

変数が宣言/設定解除されているかどうかを確認する関数

空を含む $array=()


@Gillesの答えに加えて

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

-それを関数内にカプセル化する方法を見つけられませんでした- リチャード・ハンセン答えに一部基づいている単純なバージョンを追加したいと思いますが、空で発生する落とし穴にも対処しますarray=()

# The first parameter needs to be the name of the variable to be checked.
# (See example below)

var_is_declared() {
    { [[ -n ${!1+anything} ]] || declare -p $1 &>/dev/null;}
}

var_is_unset() {
    { [[ -z ${!1+anything} ]] && ! declare -p $1 &>/dev/null;} 
}
  • 変数が(未)設定されているかどうかを最初にテストすることにより、必要でない場合は、宣言の呼び出しを回避できます。
  • ただし$1、emptyの名前が含まれている場合$array=()、declareを呼び出すと、正しい結果が得られます
  • 変数が設定されていないか空の配列の場合にのみdeclareが呼び出されるため、/ dev / nullに渡されるデータは多くありません。


次のコードを使用して、機能をテストできます。

( # start a subshell to encapsulate functions/vars for easy copy-paste into the terminal
  # do not use this extra parenthesis () in a script!

var_is_declared() {
    { [[ -n ${!1+anything} ]] || declare -p $1 &>/dev/null;}
}

var_is_unset() {
    { [[ -z ${!1+anything} ]] && ! declare -p $1 &>/dev/null;} 
}

:;       echo -n 'a;       '; var_is_declared a && echo "# is declared" || echo "# is not declared"
a=;      echo -n 'a=;      '; var_is_declared a && echo "# is declared" || echo "# is not declared"
a="sd";  echo -n 'a="sd";  '; var_is_declared a && echo "# is declared" || echo "# is not declared"
a=();    echo -n 'a=();    '; var_is_declared a && echo "# is declared" || echo "# is not declared"
a=("");  echo -n 'a=("");  '; var_is_declared a && echo "# is declared" || echo "# is not declared"
unset a; echo -n 'unset a; '; var_is_declared a && echo "# is declared" || echo "# is not declared"
echo ;
:;       echo -n 'a;       '; var_is_unset a && echo "# is unset" || echo "# is not unset"
a=;      echo -n 'a=;      '; var_is_unset a && echo "# is unset" || echo "# is not unset"
a="foo"; echo -n 'a="foo"; '; var_is_unset a && echo "# is unset" || echo "# is not unset"
a=();    echo -n 'a=();    '; var_is_unset a && echo "# is unset" || echo "# is not unset"
a=("");  echo -n 'a=("");  '; var_is_unset a && echo "# is unset" || echo "# is not unset"
unset a; echo -n 'unset a; '; var_is_unset a && echo "# is unset" || echo "# is not unset"
)

スクリプトは戻るはずです

a;       # is not declared
a=;      # is declared
a="foo"; # is declared
a=();    # is declared
a=("");  # is declared
unset a; # is not declared

a;       # is unset
a=;      # is not unset
a="foo"; # is not unset
a=();    # is not unset
a=("");  # is not unset
unset a; # is unset

-1

スカラー型と配列型の両方で機能するbash関数:

定義

has_declare() { # check if variable is set at all
    local "$@" # inject 'name' argument in local scope
    &>/dev/null declare -p "$name" # return 0 when var is present
}

呼び出し

if has_declare name="vars_name" ; then
   echo "variable present: vars_name=$vars_name"
fi
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.