arrays - Inconsistencies when removing elements from a Bash array
问题描述
When using bash arrays, you can remove an element in the following manner:
unset array[i] # where i is the array index
The problem with this is after the unset ${array[@]] is not truly valid. Yes it does give you the number of active array elements, but not the actual array depth. The index of the removed index in the array still exists. It simply has been set inactive/null. For example:
declare -a array=( a b c d e )
unset array[2]
for ((i=0; i < ${#array[@]}; i++)) ; do
echo "$i: ${array[$i]}"
done
outputs the following:
0: a
1: b
2:
3: d
array[2] is still there but set to null or inactive
array[4] (e) does not show because ${#array[@]} is the number of active array elements and not the true array element depth. This gets very messy very quickly each time an element is unset
As an example consider the following code:
# array contains 0 or more strings # remove looks for and removes a given string
remove () {
local str=$1
for (( i = 0 ; i < ${#array[@]}; i++ )) ; do
if [[ "${array[$i]}" == "$str" ]] ; then
unset array[$i]
return 0
fi
done
echo "$str: not registered"
return 0
}
This is only valid the first time remove is called. After that, valid elements may be missed.
One fix for this is to added the following line after the unset:
unset array[$i]
+ array=( "${array[@]}" )
This re-initializes array with the element completely removed.
The problem, this feels kludgy.
So my questions are this:
1) is there a way of getting the true array element depth?
2) is there a way of detecting the end of an array when iterating through it?
3) is there another cleaner solution?
解决方案
了解为什么 for ((i=0; i<${#array[@]}; i++))
会损坏
从您在这里要求的意义上说,没有“真正的数组元素深度”之类的东西。Bash 数组并不是真正的数组——它们是哈希映射(常规数组的数字索引,bash 4.0 的新“关联数组”的字符串索引)。因此,键绝对没有理由从 0 开始——你可以有一个像下面这样的数组:declare -a array=( [1000]="one thousand" [2000]="two thousand" [3000]="three thousand" )
,它的长度正好是 3;这些项目之间没有一堆 NUL/空元素(分别用 keys和1000
查找)。2000
3000
安全地从稀疏数组中删除元素
如果要按索引删除,请遍历索引。虽然"${array[@]}"
迭代数组中的项目,但"${!array[@]}"
(注意!
)通过可以查找这些项目的索引进行迭代。
正如您所观察到的,假设索引范围从 0 到数组中的项目总数是不安全的,因为 bash 数组可以是稀疏的——但是没有理由编写代码来在第一名。
for array_idx in "${!array[@]}"; do
unset "array[$array_idx]"
done
推荐阅读
- c# - 多个数据从数据库显示到同一视图中
- javascript - 如何切换 html css js 键盘中的符号?
- c++ - 如何使用 + 运算符在 cpp 中添加字符串和数字?
- mysql - JSON_EXTRACT 和 mysql 局部变量做错了什么
- google-calendar-api - 日历 ACL 看起来不适用于外部域
- boolean - 带火炬的矢量/矩阵产品,包括布尔值
- c++ - OpenSSL 读取非阻塞套接字意外行为
- nginx - GCP VM 将所有请求重定向到另一个 URL
- elasticsearch - (elasticsearch)不区分大小写的模式分析器无法按预期工作(已解决 - 用户错误)
- javascript - 我需要在我的字符串中过滤连字符(-)和空格(“”),我做错了什么?