1

I'm currently learning shell scripting and I was trying to delete an element during iterations for finding max element in an array. This is just an example:

declare -a array=(1 2 3 4)
x=2     #Can I do it without making another variable?
array=( "${array[@]/$x}" )  
echo ${array[@]}

This works fine for me but I wonder if there's anyway do this without x=2, since array=( "${array[@]/$2}" ) doesn't work. Thank you.

Anurag Srivastava
  • 14,077
  • 4
  • 33
  • 43
Chocode
  • 147
  • 9
  • 2
    `unset array[2]` – Shawn Feb 17 '22 at 08:01
  • Wow..such an easy way – Chocode Feb 17 '22 at 08:04
  • 1
    `unset array[2]` does not always work. `unset 'array[2]'` always works. For a variable index use `unset "array[$x]"`. See [Bash Pitfalls #57 (unset unquoted array element)](https://mywiki.wooledge.org/BashPitfalls#unset_a.5B0.5D). – pjh Feb 17 '22 at 10:40
  • @ChoiChangWoo `array=( "${array[@]/$x}" )` does **not** work for you. It only **apparently** works. Carefully read the excellent answer below and you'll understand why. – Renaud Pacalet Feb 17 '22 at 12:58

1 Answers1

1

To delete an array element by number use unset. Examples:

  1. unset 'array[2]'
  2. unset "array[$n]"
  3. unset 'array[n]'

The quotes are essential in all cases. See Bash Pitfalls #57 (unset unquoted array element).

Examples 2 and 3 have exactly the same effect (assuming that the value of variable n is a valid array index). Example 3 works because Bash doesn't require a preceding $ to expand variables in contexts that support arithmetic, including array indexes.

Note that using unset on an array index does not change other array indexes. It produces an array with holes in it (aka a sparse array). See Arrays [Bash Hackers Wiki] for more information.

echo ${array[@]} is broken in several ways. Use Shellcheck to find problems like this. echo "${array[@]}" is better (and accepted by Shellcheck) but still broken. One way that it can fail is if the first element of the array is a valid echo option (-n, -e, or -E).

To see exactly what is in array (revealing holes if there are any) use:

declare -p array

For example

array=(a b c d)
declare -p array
n=2
unset 'array[n]'
declare -p array

outputs

declare -a array=([0]="a" [1]="b" [2]="c" [3]="d")
declare -a array=([0]="a" [1]="b" [3]="d")

(note the missing index 2 in the second output line).

Beware that array=( "${array[@]/$x}" ) does not delete any array element. It just removes the first occurrence of the string in $x from each element in the array.

For example

array=(12321 32123)
declare -p array
x=2
array=( "${array[@]/$x}" )
declare -p array

outputs

declare -a array=([0]="12321" [1]="32123")
declare -a array=([0]="1321" [1]="3123")

The example in the question

declare -a array=(1 2 3 4)
x=2
array=( "${array[@]/$x}" )
declare -p array

outputs

declare -a array=([0]="1" [1]="" [2]="3" [3]="4")

The second array element (index 1) has not been removed. It's just been set to the empty string.

There's some useful information in Remove an element from a Bash array. However, the question is about deleting array elements with particular values, not deleting elements by index. Also, a lot of the answers (including the accepted (and much-upvoted) one) have serious problems. Many of the problems are identified in comments, but some of the comments are also very wrong. Be careful.

pjh
  • 6,388
  • 2
  • 16
  • 17