bash - 配列 - シェルスクリプト 変数 null 代入




変数がBashに設定されているかどうかを確認するには? (20)

変数がBashに設定されているかどうかを知るには?

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

function a {
    # if $1 is set ?
}

変数が宣言されているかどうかをチェックする関数

空を含む $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空の名前が含まれている場合$array=()、declareを呼び出すと適切な結果が得られます
  • 変数が設定されていないか空の配列の場合にのみ、declareが呼び出されるため、/ dev / nullに渡されるデータは決してありません。

この関数は、次の条件で示されるようにテストします。

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

詳細については

およびテストスクリプトは、私の見るanswerの質問には、「変数がbashで存在する場合、どのようにチェックしますか?」

備考:のanswerでdeclare -pも示されているように、同様の使い方は本当に偶然です。そうでなければ私はもちろんそれを信用しているだろう!answer


(通常)正しい方法

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

${var+x}は、 varが設定されていない場合は何も評価されないパラメータ拡張であり、そうでない場合はxを代入します。

引用漏れ

この構文と使用法は、引用符を必要としないものに展開することを保証しているので(引用符を省略することができます( ${var+x}代わりに"${var+x}"と書くことができます) (つまり、引用符を必要としない単語区切りを含む)か、 [ -z ]結果になり、 [ -z ] [ -z "" ]と同じように同じ値(便宜的に評価されます)になります)。

しかし、引用符は安全に省略することができますが、すぐには分かりませんでした(これはBashの主要なコーダーでもある引用符の説明の最初の著者には明らかではありませんでした)。 O(1)速度ペナルティの可能な限り小さいコストで、 [ -z "${var+x}" ]と引用符を[ -z "${var+x}" ] 。 最初の著者は、この解決策を使用しているコードの隣にこのコメントを追加しました。この答えにURLを付けました。引用符を安全に省略できる理由についての説明も含まれています。

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

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

設定されていない変数と空の文字列に設定された変数を区別しないため、これはしばしば間違っています。 つまり、 var=''ならば、上記の解は "var is blank"を出力します。

unsetと "空文字列に設定"の区別は、ユーザーが拡張子またはプロパティーの追加リストを指定しなければならない状況で必須であり、空白でない値を指定しない場合は空の文字列を指定する必要があります。スクリプトが空の拡張子または追加のプロパティのリストを使用するようにします。

この区別はすべてのシナリオでは必須ではないかもしれません。 それらの場合[ -z "$var" ]はうまくいくでしょう。


bashでは、 [[ ]]組み込みの中で-vを使うことができます:

#! /bin/bash -u

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

echo $SOMEVAR

nullでない/非ゼロの文字列変数をチェックするには、

if [ -n "$1" ]

それは-zの反対です。 私は自分自身が-nよりも-zを使っているのを見つけました。


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

例えば:

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

first_argが割り当てられている場合は$1設定され、そうでない場合は "foo"という値が使用されます。 絶対に単一のパラメータを取る必要があり、適切なデフォルトが存在しない場合は、パラメータが与えられていないときにエラーメッセージで終了することができます:

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

(この例では、 $1で何もしたくないので、これを設定しないと終了します)


varが配列の場合、 [ -z "${var+x}" ]パラメータの置換は正しくありません。 Bashでは、以下のように、 [ "${#var[@]}" = 0 ]ような配列構文を使用する必要があります。

is-var-set () {
    results="\${var+x}=${var+x}\t\${#var[@]}=${#var[@]}"
    if [ -z "${var+x}" ] && [ "${#var[@]}" = 0 ]; then
        echo -e "$1: var's unset.\t$results"
    elif [ -n "${var+x}" ] && [ "${#var[@]}" != 0 ]; then
        echo -e "$1: var is set. \t$results"
    else
        echo -e "$1: Is var set? \t$results"
    fi
    unset var # so we don't have to do it everywhere else
}

ほとんどの場合、彼らは同意します。 私が見つけた唯一の状況は、配列メソッドがより正確なところです。変数が位置0空でない配列である場合です(たとえば、テスト7Aで)。 この不一致は、 $var${var[0]}省略しているために発生し${var[0]}したがって、 [ -z "${var+x}" ]は配列全体をチェックしていません。

ここに私のテストケースがあります。

unset var;      is-var-set 1 # var unset
var='';         is-var-set 2 # var[0] set to ''
var=foo;        is-var-set 3 # var[0] set to 'foo'
var=();         is-var-set 4 # var unset (all indices)
var=(foo);      is-var-set 5 # var[0] set to 'foo'
var=([0]=foo);  is-var-set 6 # var[0] set to 'foo'
var=([1]=foo);  is-var-set 7 # var[0] unset, but var[1] set to 'foo'
declare -a var; is-var-set 8 # var empty, but declared as an array
declare -A var; is-var-set 9 # var empty, but declared as an associative array
declare -A var  # Because is-var-set() conveniently unsets it
var=([xz]=foo); is-var-set A # var[xz] set to 'foo', but var's otherwise empty
declare -a var  # Demonstrate that Bash knows about var, even when there's
declare -A var; is-var-set B # apparently no way to just _check_ its existence

ここに出力があります。

1: var's unset. ${var+x}=       ${#var[@]}=0
2: var is set.  ${var+x}=x      ${#var[@]}=1
3: var is set.  ${var+x}=x      ${#var[@]}=1
4: var's unset. ${var+x}=       ${#var[@]}=0
5: var is set.  ${var+x}=x      ${#var[@]}=1
6: var is set.  ${var+x}=x      ${#var[@]}=1
7: Is var set?  ${var+x}=       ${#var[@]}=1
8: var's unset. ${var+x}=       ${#var[@]}=0
9: var's unset. ${var+x}=       ${#var[@]}=0
A: Is var set?  ${var+x}=       ${#var[@]}=1
./foo.sh: line 26: declare: var: cannot convert indexed to associative array
B: var's unset. ${var+x}=       ${#var[@]}=0

要するに:

  • ${var+x}パラメータ拡張構文は、ほとんどの場合、関数へのパラメータのチェックなど、 ${#var[@]}配列構文と同様に機能します。 このケースが壊れる唯一の方法は、Bashの将来のバージョンが、コンテンツを個々の引数に変換することなく配列を関数に渡す方法を追加する場合です。
  • 配列の構文は、要素0設定していない配列(結合または非結合)に対しては必要です。
  • どちらの構文も、配列のどこかにヌル値を割り当てなくてもdeclare -a vardeclare -a varされている場合、何が起きているかを説明していません。 Bashは依然として(上記のテストB見られるように)ケースをどこかで区別しているので、この答えは間違いありません。 幸いにもBashは、プログラム/スクリプトの実行時に、エクスポートされた環境変数を文字列に変換するので、宣言された変数の問題は、少なくとも他のスクリプトのソースがない場合は、単一のスクリプトに含まれます。

あなたが[email protected]何かをチェックしたいなら、これを行うための(もっと)良いコードを見つけました。

if [[ $1 = "" ]]
then
  echo '$1 is blank'
else
  echo '$1 is filled up'
fi

なぜこのすべて? [email protected]すべてがBashに存在しますが、デフォルトでは空白なので、 test -ztest -ntest -nと手助けできませんでした。

更新:パラメータ内の文字数をカウントすることもできます。

if [ ${#1} = 0 ]
then
  echo '$1 is blank'
else
  echo '$1 is filled up'
fi

これは私が毎日使っているものです:

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

これはLinuxとSolarisの下でbash 3.0にうまくいきます。

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

できるよ:

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

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

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

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

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

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"モードで定義されているかどうかをテストする方法


変数がバインドされているかアンバインドされているかをテストしたい場合は、nounsetオプションをオンにしてもうまくいきます:

set -o noun set

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

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

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

変数のタイプ(env変数、パラメータ、または通常の変数)に従ってチェックするのが最善です。

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
   return $?
}
declare_var "var_name" && echo "Set" || echo "Unset"

ノート:

  • $#は、位置パラメータの数を示します。
  • declare -pパラメータとして渡される変数の定義を提供します。 存在する場合は0を返し、そうでない場合は1を返し、エラーメッセージを出力します。
  • $? 最後に実行したコマンドのステータスコードを表示します。

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

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

パラメータが渡されたかどうかを調べるには、関数に渡されるパラメータの数である$#テストします(関数の中にないときはスクリプトに渡します)( Paulの答えを参照)。


私の好みの方法はこれです:

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

基本的に、変数が設定されていれば、結果は「結果のfalse 」の否定になりfalsetrue = "set is")。

そして、もしそれが設定されていなければ、それは "結果のtrue否定"(空の結果がtrue評価されるので)になりtrue (したがって、 false = "NOT set"として終了しfalse )。


私はいつもこのコードを最初に見た人が理解しやすいように、これを使っています:

if [ "$variable" = "" ]
    then
    echo "Variable X is empty"
fi

空でないかどうかチェックしたい場合は、

if [ ! "$variable" = "" ]
    then
    echo "Variable X is not empty"
fi

それでおしまい。


私は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} ]
}

私が最初にこの実装(JensとLionelの答えに触発された)にバグを持っていたので、私は別の解決策を思いつきました:

# 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

必要なすべての変数が宣言された状態で呼び出された場合:

こんにちは世界!

else:

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


[[ $foo ]]

または

(( ${#foo} ))

または

let ${#foo}

または

declare -p foo

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

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






variables