Ant*_*ber 15 bash array variable
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.
Run Code Online (Sandbox Code Playgroud)
Why, in line 13, is the stdout blank, considering that the array seems to have been updated judging by line 12's stdout?
And therefore, what should I do to get the intended answer, "69"?
Joh*_*024 22
unset
removes an element. It doesn't renumber the remaining elements.
We can use declare -p
to see exactly what happens to 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")
Run Code Online (Sandbox Code Playgroud)
Observe the numbers
no longer has an element 4
.
Observe:
$ a=()
$ a[1]="element 1"
$ a[22]="element 22"
$ declare -p a
declare -a a=([1]="element 1" [22]="element 22")
Run Code Online (Sandbox Code Playgroud)
Array a
has no elements 2 through 21. Bash does not require that array indices be consecutive.
Let's start with the numbers
array with the missing element 4
:
$ declare -p numbers
declare -a numbers=([0]="53" [1]="8" [2]="12" [3]="9" [5]="69" [6]="8" [7]="7" [8]="1")
Run Code Online (Sandbox Code Playgroud)
If we would like the indices to change, then:
$ numbers=("${numbers[@]}")
$ declare -p numbers
declare -a numbers=([0]="53" [1]="8" [2]="12" [3]="9" [4]="69" [5]="8" [6]="7" [7]="1")
Run Code Online (Sandbox Code Playgroud)
There is now an element number 4
and it has value 69
.
Again, let's define numbers
:
$ numbers=(53 8 12 9 784 69 8 7 1)
Run Code Online (Sandbox Code Playgroud)
As suggested by Toby Speight in the comments, a method to remove the fourth element and renumber the remaining elements all in one step:
$ 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")
Run Code Online (Sandbox Code Playgroud)
As you can see, the fourth element was removed and all remaining elements were renumbered.
${numbers[@]:0:4}
slices array numbers
: it takes the first four elements starting with element 0.
Similarly, ${numbers[@]:5}
slice array numbers
: it takes all elements starting with element 5 and continuing to the end of the array.
The values of an array can be obtained with ${a[@]}
. To find the indices (or keys) that correspond to those values, use ${!a[@]}
.
For example, consider again our array numbers
with the missing element 4
:
$ declare -p numbers
declare -a numbers=([0]="53" [1]="8" [2]="12" [3]="9" [5]="69" [6]="8" [7]="7" [8]="1")
Run Code Online (Sandbox Code Playgroud)
To see which indices are assigned:
$ echo "${!numbers[@]}"
0 1 2 3 5 6 7 8
Run Code Online (Sandbox Code Playgroud)
Again, 4
is missing from the list of indices.
From man bash
:
该
unset
内建是用来摧毁阵列。unset name[subscript]
销毁 index 处的数组元素subscript
。索引数组的负下标按上述解释。必须小心避免由路径名扩展引起的不必要的副作用。unset name
, wherename
is an array, orunset name[subscript]
, wheresubscript
is*
or@
, 删除整个数组。
bash
像 inksh
这样的数组并不是真正的数组,它们更像是键限制为正整数的关联数组(或所谓的稀疏数组)。对于具有真实数组的外壳,您可以查看诸如rc
, es
, fish
, yash
, 之类的外壳zsh
(甚至csh
/tcsh
尽管这些外壳有很多问题,但最好避免)。
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
Run Code Online (Sandbox Code Playgroud)
(注意,在 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
Run Code Online (Sandbox Code Playgroud)
fish
(不是与bash
/相反的类似 Bourne 的外壳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
Run Code Online (Sandbox Code Playgroud)
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})
Run Code Online (Sandbox Code Playgroud)
ksh
和bash
如果您这样做,您可以将数组用作普通数组:
a=("${a[@]}")
Run Code Online (Sandbox Code Playgroud)
在每次删除或插入操作之后,可能使索引列表不连续或不从 0 开始。还要注意ksh
/bash
数组从 0 开始,而不是 1(除了$@
(在某些方面))。
这实际上会整理元素并将它们按顺序移动到索引 0、1、2...。
另请注意,您需要引用number[i]
in:
unset 'number[i]'
Run Code Online (Sandbox Code Playgroud)
否则,unset numberi
如果numberi
在当前目录中调用了一个文件,它将有效地运行。