我想创建一个带有像这样的bash数组的函数:
a=("element zero" "element one" "element two")
并删除一个元素,如"元素一"并留下这样的数组:
a=("element zero" "element two")
这样echo $a[1]
将打印element two
而非zero
。
我已经看过几次尝试,但没有找到一个干净利落地完成它或没有破坏多个元素空间的元素。或者只是将元素设置为空白(即不移动后续数组元素的索引)。
答案 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
这会使稀疏数组中的未设置元素变平。