# 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“数组”实际上是存储为链表或哈希表[在关联情况下],根本不是数组,因此稀疏数组是内存效率的),删除操作要快得多。
如果您检索时向数组询问其键而不是在外部提供它们,这不会破坏您遍历数组的能力,如下所示:
for key in "${!a[@]}"; do
value="${a[$key]}"
echo "Entry $key has value $value"
done