如何在 Bash 中取消设置数组范围

如何在 Bash 中取消设置数组范围

我正在尝试删除数组元素的范围,但失败了。

我的阵列

root@ubuntu:~/work# echo ${a[@]}
cocacola.com airtel.com pepsi.com

打印 0-1 数组看起来没问题

root@ubuntu:~/work# echo ${a[@]::2}
cocacola.com airtel.com

现在我尝试使用以下方法仅删除这些元素:

root@ubuntu:~/work# unset a[@]::2
root@ubuntu:~/work# echo ${a[@]}

它删除整个数组..

我做错了什么?

我找到了删除数组范围的其他方法,但为什么上述方法不起作用?

for ((i=0; i<2; i++)); do unset a[$i]; done

编辑我也尝试过但没有运气

unset -v 'a[@]::2'

答案1

要记住的一件事是,bash像 这样的实现数组ksh,即作为关联数组,其中键仅限于正整数(与其他语言相反,例如perlzsh例如)。

在:

a[123]=foo a[456]=bar a[789]=baz

在 bash 中,您有一个包含 3 个元素的关联数组,而在 bash 中perl,您有一个包含 790 个元素的数组(zsh 为 789 个元素)。

kshor中bash${a[@]:0:1}返回按键按数字排序的元素列表中数组的第一个元素,其中键大于或等于 0。因此在这种情况下,它返回${a[123]},而不是${a[0]}

unset 'a[123]'

(记住引用它,否则如果当前目录中有一个名为 a1 或 a2 或 a3 的文件,它将失败)是有道理的,因为它删除了数组中的特定键。

unset 'a[@]::2'

但意义不大。bash只理解unset a,unset 'a[123]'unset 'a[*/@]',之后的任何内容都会被忽略,因此unset 'a[@]::2'unset 'a[@]please'执行相同的操作:取消设置整个数组。

如果要取消设置一系列键,则需要循环遍历这些键:

要获取数组的键列表,语法为"${!a[@]}"。不幸的是,应用范围不适用于bashnor ksh,因此您需要一个临时数组:

keys=("${!a[@]}")
for i in "${keys[@]::2}"; do unset "a[$i]"; done

现在,如果您想像其他语言一样考虑这些数组,那么您不想使用unset.例如,如果数组一开始就不是稀疏的,并且您希望保持它的稀疏性(即将所有元素移动 2,而不是取消设置前两个),您可以执行以下操作:

a=("${a[@]:2}")

也就是说,使用要保留的元素列表重新分配数组。

为了比较,与zsh.

a=({1..20})
unset 'a[12,16]'

会将元素 12 到 16 设置为空值。 whileunset 'a[16,20]'会将数组缩小到 15 个元素。

a=({1..20})
a[12,16]=()

(仍然是zsh)会将元素 17 到 20 移动 5 个位置,因此a[12]将包含17

答案2

  1. 如果你的数组是连续/非稀疏(0..N-1 组中的所有元素)

    您可以使用以下命令删除数组的第二个元素

    unset 'a[1]'
    

    要删除第二个、第三个和第四个元素,您可以使用例如

    for ((i=1; i<=3; i++)); do unset "a[$i]"; done
    

    要删除除第一个和第二个元素之外的所有元素,您可以使用例如

    for ((i=2; i<${#a[@]}; i++)); do unset "a[$i]"; done
    
  2. 通用解决方案(也适用于稀疏数组):您可以使用以下命令删除数组的第二个元素

    unset "a[$(echo ${!a[@]} | cut -d" " -f 2)]"
    

    要删除第二个、第三个和第四个元素,您可以使用例如

    for $(echo ${!a[@]} | cut -d" " -f 2-4) ; do unset "a[$i]"; done
    

    要删除除第一个和第二个元素之外的所有元素,您可以使用例如

    for $(echo ${!a[@]} | cut -d" " -f 2-) ; do unset "a[$i]"; done
    

相关内容