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")
Observe the numbers
no longer has an element 4
.
Another example
Observe:
$ a=()
$ a[1]="element 1"
$ a[22]="element 22"
$ declare -p a
declare -a a=([1]="element 1" [22]="element 22")
Array a
has no elements 2 through 21. Bash does not require that array indices be consecutive.
Suggested method to force a renumbering of the indices
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")
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")
There is now an element number 4
and it has value 69
.
Alternate method to remove an element & renumber array in one step
Again, let's define numbers
:
$ numbers=(53 8 12 9 784 69 8 7 1)
As suggested by Toby Speight in the comments, a method to remove the fifth element (at index 4) 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")
As you can see, the fifth 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.
Obtaining the indices of an 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")
To see which indices are assigned:
$ echo "${!numbers[@]}"
0 1 2 3 5 6 7 8
Again, 4
is missing from the list of indices.
Documentation
From man bash
:
The unset
builtin is used to destroy arrays. unset name[subscript]
destroys the array element at index subscript
.
Negative subscripts to indexed arrays are interpreted as described above. Care must be taken to avoid unwanted side effects caused by pathname expansion. unset name
, where name
is an array, or unset name[subscript]
, where subscript
is *
or @
, removes the entire
array.