如果数组变量被赋值为“()”,为什么不被认为是设置的?

如果数组变量被赋值为“()”,为什么不被认为是设置的?

bash手册说:

参数是存储值的实体

变量是由名称表示的参数。

如果参数已被赋值,则该参数被设置。

如果下标已被赋值,则数组变量被视为已设置。

数组变量是变量还是参数?

如果是,为什么数组变量在分配时不被视为设置()

$ ar=()
$ echo ${ar-This is a new value}
This is a new value

谢谢。

答案1

Inbash与 in 一样ksh,其中$var是一个数组,$var实际上是 的缩写${var[0]}

所以在:

var=([1]=whatever [2]=blah)

${var+set}不会扩展为set,并且[[ -v var ]]会返回 false,因为$var没有索引为 0 的元素(请注意,在 中bash,与 in 类似ksh,但与大多数其他 shell 和语言相反,数组是稀疏数组,或者键仅限于正整数的关联数组)。

bash(至少从 4.3 开始)中,当您使用以下命令将变量声明为数组时:

typeset -a var

var最初未设置。它甚至没有设置为空列表。在 中4.3typeset -p var将返回错误。在 4.2 及之前版本中,它会输出:

declare -a a='()'

(就像声明数组分配了一个空列表一样,就像在 中一样zsh

在4.4中,输出:

declare -a var

因此,从 4.3 开始,未设置(但已声明)的数组与分配了空列表的数组不同。

尽管如此,还是很难通过编程来区分两者。但在实践中,这种区别并不是很有用。最有可能的是,您想知道数组中有多少个元素:

((${#array[@]})) || echo array has no element

请参阅zshrcfishyash了解具有更好阵列设计的 shell。

答案2

如果未设置,该构造${var-foo}将扩展为foovar或为空。空数组就是这样。

正如你引用的:

如果下标已被赋值,则数组变量被视为已设置。

您站点 ( ) 的示例ar=()未向任何下标分配值。

答案3

测试整个数组的正确方法是:

[[ ${ar[@]+set} == set ]] && echo "array has a value may be a null"

您编写的是对索引 0 处的值的测试。这两个是等效的:

${ar+set}
${ar[0]+set}

但两者都只会测试索引零处的数组是否已设置,而不是整个数组,我认为这就是您的意思。

但是,对于你的问题:如果分配(),为什么数组未设置?

因为你有不是为任何数组索引分配任何值,甚至不包括 null。
要设置一些索引(以及数组),您需要类似以下内容:

$ declare -a ar=([3]="value")

甚至:

$ declare -a ar=([3]="")

zsh(即使在 sh 或 ksh 模拟中)是所有测试的 shell 中唯一一个(像往常一样,特殊的 shell)将数组声明为:

$ unset ar; typeset -a ar=(); echo $(typeset -p ar) ${ar[@]+set}

评论中的问题:

谢谢。这里的ar[@]可以换成ar[*]吗?它们是数组变量吗?

不,an"${ar[*]}"是所有数组值的字符串串联。

然而,在这个特定的扩展中:“${ar[*]+set}”两者是等价的。

从手册(在数组):

如果下标是@或*,则该词将扩展到name的所有成员。

相关内容