我正在编写一个脚本,我发现了一些我不理解的未初始化和未设置数组变量的意外行为。
首先是长度:
$ echo ${#notset[@]}
0
$ uninitialized=
$ echo ${#uninitialized[@]}
1
为什么uninitialized
长度是1?不应该是零吗?是因为空变量被视为一个空元素的数组吗?
这一事实导致了一些问题。例如,假设我想创建一个数组,并根据用户命令行参数插入一定数量的内容。我想我可以做类似(+)的事情:
myarray=
if [ some-condition ]
then
myarray[${#myarray[@]}]=some-value
fi
if [ some-condition2 ]
then
myarray[${#myarray[@]}]=some-value2
elif [ some-condition3 ]
then
myarray[${myarray[@]}]=some-value3
myarray[${myarray[@]}]=some-value4
fi
但这将第一个槽保留为空,这是我不喜欢的,并且还破坏了我编写的一些代码(*),此时假设我想查看数组是否包含任何元素。我该怎么做呢?
[ -z "${myarray[@]}" ]
如果数组包含多个元素,则会引发错误。
[ -z "$myarray" ]
失败,因为第一个元素为空,即使数组不为空。
那么,我应该如何控制数组未初始化呢?
有人可以解释一下在处理时到底发生了什么吗数组和 unset - 未初始化的变量?
(+)我知道我可以避免“声明”变量并且它会起作用,但是这个脚本将由教授审查,并且他不喜欢在随机位置定义变量。
(*)在尝试这个事情之前,我将数组的长度保存在另一个变量中,所以我没有遇到问题。但我想避免定义这个辅助变量,因为我知道没有它们我也可以获得长度。
答案1
您可以看到以下差异declare -p
:
unset foo
declare -a foo
declare -p foo
# prints declare -a foo='()'
foo=
declare -p foo
# prints declare -a foo='([0]="")'
如果您想初始化一个空数组,第一个输出declare -p
是声明它的最佳方法的一个很好的提示:
declare -a array='()'
(该declare -a
部分可能是可选的,简单的array=()
应该也可以。)
如果要测试数组是否有 0 个元素,请使用${#array[@]}
;上的数值比较不要尝试test -z
对扩展进行操作,因为在许多情况下不会给出正确的结果。
答案2
要初始化空数组,请使用
array=()
要将值添加到数组中,请使用
array+=(value)