间接引用bash数组会创建一个空元素。为什么?

时间:2016-07-29 20:06:18

标签: arrays bash

为什么空的bash数组长度为1?这让我疯了。任何人都可以解释array3发生的事情吗?

$ bash
$ echo $BASH_VERSION
4.3.11(1)-release
$ set | egrep '(array1|array2|array3|indirect)'
$ array1=(); echo ${#array1[@]}
0
$ declare -a array2; echo ${#array2[@]}
0
$ indirect=array1; array3=${!indirect}; echo ${#array3[@]}
1
$ echo "what's in here? ->${array3[0]}<-"
what's in here? -><-
$ set | egrep '(array1|array2|array3|indirect)'
array1=()
array3=
indirect=array1

我通过尝试一个独特的appender&#34;对于bash数组的函数,结果在开头时保持了额外的空元素。谢谢你的聆听; - )

1 个答案:

答案 0 :(得分:2)

发生了什么

这不符合你的想法:

array1=( )
indirect=array1
array3=${!indirect}

...这不是,而且从来就不是,是创建间接命名数组内容副本的语法。相反,它将空字符串(空array1中的第一个条目)分配给array3

$ declare -p array3
declare -- array3=""

考虑一个不那么令人困惑的例子:

$ array1=( hello cruel world )
$ indirect=array1
$ echo ${!indirect}
hello

...也就是说你间接执行了作业array3=$array1(将array1中的第一个元素指定给名为array3的字符串),不< / strong> array3=( "${array1[@]}" )(创建一个名为array3的数组,其内容与数组array1相同。)

使用namevars的间接数组变异(即间接追加,正确的方式)

如果您的目标是bash 4.3,那么该语言的新增内容(或者说,最近采用的ksh功能)就是为了这个目的:namevars。

append_if_unique() {
  local varname=$1; shift

  # create a new global array if our destination doesn't already exist
  declare -p "$varname" >/dev/null 2>&1 || declare -g -a "$varname"

  # avoid nasty corner cases around locals colliding with destination
  if [[ $varname =~ ^(varname|var|value|new_value)$ ]]; then
    echo "ERROR: cannot append to a variable named $varname" >&2
    return 1
  fi

  local -n var="$varname"
  local value new_value

  for new_value; do
    for value in "${var[@]}"; do
      if [[ $value = "$new_value" ]]; then
        continue 2 # skip to next proposed new value
      fi
    done
    var+=( "$new_value" )
  done
}

...此后:

append_if_unique myarray "first value" "second value" "first value"
append_if_unique myarray "first value" "third value"
declare -p myarray

......会发出......

declare -a myarray='([0]="first value" [1]="second value" [2]="third value")'

独特追加bash,简单方法

...但是,除非要求保留订单,否则根本不需要花哨的功能。只需使用关联数组:

declare -A myarray
myarray["first value"]=1
myarray["second value"]=1
myarray["third value"]=1
myarray["third value"]=1

...此后:

# iterate over keys with ${!yourarray[@]} to access
for key in "${!myarray[@]}"; do
  printf '%s\n' "$key"
done