如何在不展平数组的情况下从bash数组中删除元素

时间:2014-08-21 22:31:05

标签: bash

我想创建一个带有像这样的bash数组的函数:

a=("element zero" "element one" "element two")

并删除一个元素,如"元素一"并留下这样的数组:

a=("element zero" "element two")

这样echo $a[1]将打印element two而非zero

我已经看过几次尝试,但没有找到一个干净利落地完成它或没有破坏多个元素空间的元素。或者只是将元素设置为空白(即不移动后续数组元素的索引)。

2 个答案:

答案 0 :(得分:5)

# initial state
a=( "first element" "second element" "third element" )

# to remove
unset a[0]

# to reindex, such that a[0] is the old a[1], rather than having the array
# start at a[1] with no a[0] entry at all
a=( "${a[@]}" )

# to print the array with its indexes, to check its state at any stage
declare -p a

...现在,对于一个函数,如果你有bash 4.3,你可以使用namevars来完成这个,而不需要任何eval

remove() {
  local -n _arr=$1      # underscore-prefixed name to reduce collision likelihood
  local idx=$2
  unset _arr[$idx]      # remove the undesired item
  _arr=( "${_arr[@]}" ) # renumber the indexes
}

对于旧版本的bash,它有点粘:

remove() {
  local cmd
  unset "$1[$2]"
  printf -v cmd '%q=( "${%q[@]}" )' "$1" "$1" && eval "$cmd"
}

使用带有printf格式字符串的%q有点偏执 - 这使得恶意选择的值(在本例中为变量名称)更难以执行他们选择的操作,如反对简单地失败而没有效果。


所有这一切 - 如果你重新编号你的阵列,它会更好。如果你不进行重新编号步骤,那么在删除条目a[1]后,你只需要一个稀疏数组,该索引没有内容(这与该索引处的空字符串不同 - bash&#34 ;数组"实际上存储为链接列表或哈希表[在关联案例中],而不是作为数组存储,因此稀疏数组是内存效率的,删除操作要快得多。

如果你检索要求数组输入密钥而不是在外部提供密钥,这并不会破坏你的数组迭代的能力,如:

for key in "${!a[@]}"; do
  value="${a[$key]}"
  echo "Entry $key has value $value"
done

答案 1 :(得分:0)

remove() { 
    eval "$1=( \"\${$1[@]:0:$2}\" \"\${$1[@]:$(($2+1))}\" )" 
}

可以像这样调用:

a=("element zero" "element one" "element two")
remove a 1
echo ${a[@]}  #element zero element two
echo ${a[1]}  #element two

这将留下空白数组元素。

a=("element zero" "element one" "" "element three")
remove a 1
echo ${a[@]}  #element zero element two
echo ${a[1]}  #
echo ${a[2]}  #element three

这会使稀疏数组中的未设置元素变平。