1 #!/bin/bash
2 # query2.sh
3
4 numbers=(53 8 12 9 784 69 8 7 1)
5 i=4
6
7 echo ${numbers[@]} # <--- this echoes "53 8 12 9 784 69 8 7 1" to stdout.
8 echo ${numbers[i]} # <--- this echoes "784" to stdout.
9
10 unset numbers[i]
11
12 echo ${numbers[@]} # <--- this echoes "53 8 12 9 69 8 7 1" to stdout.
13 echo ${numbers[i]} # <--- stdout is blank.
考虑到根据第 12 行的 stdout 判断数组似乎已更新,为什么第 13 行中的 stdout 为空?
因此,我应该怎样做才能得到预期的答案“69”?
答案1
unset
删除一个元素。它不会对剩余元素重新编号。
我们可以用它declare -p
来看看到底发生了什么numbers
:
$ unset "numbers[i]"
$ declare -p numbers
declare -a numbers=([0]="53" [1]="8" [2]="12" [3]="9" [5]="69" [6]="8" [7]="7" [8]="1")
观察numbers
不再有元素4
。
另一个例子
观察:
$ a=()
$ a[1]="element 1"
$ a[22]="element 22"
$ declare -p a
declare -a a=([1]="element 1" [22]="element 22")
数组a
没有元素 2 到 21。Bash 不要求数组索引是连续的。
强制对索引重新编号的建议方法
让我们从numbers
缺少元素的数组开始4
:
$ declare -p numbers
declare -a numbers=([0]="53" [1]="8" [2]="12" [3]="9" [5]="69" [6]="8" [7]="7" [8]="1")
如果我们希望改变索引,那么:
$ numbers=("${numbers[@]}")
$ declare -p numbers
declare -a numbers=([0]="53" [1]="8" [2]="12" [3]="9" [4]="69" [5]="8" [6]="7" [7]="1")
现在有一个元素编号4
并且它具有值69
。
一步删除元素并对数组重新编号的另一种方法
再次,让我们定义numbers
:
$ numbers=(53 8 12 9 784 69 8 7 1)
正如建议的托比·斯佩特在注释中,有一种方法可以一步删除第五个元素(位于索引 4 处)并对剩余元素重新编号:
$ numbers=("${numbers[@]:0:4}" "${numbers[@]:5}")
$ declare -p numbers
declare -a numbers=([0]="53" [1]="8" [2]="12" [3]="9" [4]="69" [5]="8" [6]="7" [7]="1")
正如您所看到的,第五个元素被删除,所有剩余元素都被重新编号。
${numbers[@]:0:4}
slices 数组numbers
:它获取从元素 0 开始的前四个元素。
类似地,${numbers[@]:5}
切片数组numbers
:它获取从元素 5 开始一直到数组末尾的所有元素。
获取数组的索引
这价值观可以使用 获得数组的${a[@]}
.为了找到指数(或者键) 对应于这些值,使用${!a[@]}
.
例如,再次考虑我们的数组numbers
缺少元素4
:
$ declare -p numbers
declare -a numbers=([0]="53" [1]="8" [2]="12" [3]="9" [5]="69" [6]="8" [7]="7" [8]="1")
要查看分配了哪些索引:
$ echo "${!numbers[@]}"
0 1 2 3 5 6 7 8
同样,4
索引列表中缺少该值。
文档
从man bash
:
内置
unset
函数用于销毁数组。unset name[subscript]
销毁索引处的数组元素subscript
。索引数组的负下标的解释如上所述。必须小心避免路径名扩展引起的不良副作用。unset name
,其中name
是数组,或者unset name[subscript]
,其中subscript
是*
或者@
,删除整个数组。
答案2
bash
像 in 那样的数组ksh
并不是真正的数组,它们更像是键限于正整数的关联数组(或所谓的稀疏数组)。对于具有真实数组的 shell,您可以查看诸如rc
、es
、fish
、yash
、之类的 shell zsh
(甚至csh
/tcsh
尽管这些 shell 有很多问题,但最好避免)。
在zsh
:
a=(1 2 3 4 5)
a[3]=() # remove the 3rd element
a[1,3]=() # remove the first 3 elements
a[-1]=() # remove the last element
(请注意,在 zsh 中,unset 'a[3]'
实际上将其设置为空字符串以提高与 的兼容性ksh
)
在yash
:
a=(1 2 3 4 5)
array -d a 3 # remove the 3rd element
array -d a 1 2 3 # remove the first 3 elements
array -d a -1 # remove the last element
在(不是与/fish
相反的类似 Bourne 的 shell ):bash
zsh
set a 1 2 3 4 5
set -e a[3] # remove the 3rd element
set -e a[1..3] # remove the first 3 elements
set -e a[-1] # remove the last element
在es
(基于rc
,而不是类似 Bourne 的)
a = 1 2 3 4 5
a = $a(... 2 4 ...) # remove the 3rd element
a = $a(4 ...) # remove the first 3 elements
a = $a(... `{expr $#a - 1}) # remove the last element
# or a convoluted way that avoids forking expr:
a = $a(... <={@{*=$*(2 ...); return $#*} $a})
在ksh
和bash
如果您这样做,则可以将数组用作普通数组:
a=("${a[@]}")
在每次删除或插入操作之后,这可能会使索引列表不连续或不从 0 开始。另请注意ksh
/bash
数组从 0 开始,而不是 1 (除了$@
(在某些方面))。
这实际上会整理元素并将它们按顺序移动到索引 0、1、2...。
另请注意,您需要引用以下number[i]
内容:
unset 'number[i]'
否则,如果当前目录中unset numberi
有一个文件被调用,那么它将有效地运行。numberi