I need to remove an element from an array in bash shell. Generally I'd simply do:
array=("${(@)array:#<element to remove>}")
Unfortunately the element I want to remove is a variable so I can't use the previous command. Down here an example:
array+=(pluto)
array+=(pippo)
delete=(pluto)
array( ${array[@]/$delete} ) -> but clearly doesn't work because of {}
Any idea?
The following works as you would like in bash
and zsh
:
$ array=(pluto pippo)
$ delete=pluto
$ echo ${array[@]/$delete}
pippo
$ array=( "${array[@]/$delete}" ) #Quotes when working with strings
If need to delete more than one element:
...
$ delete=(pluto pippo)
for del in ${delete[@]}
do
array=("${array[@]/$del}") #Quotes when working with strings
done
Caveat
This technique actually removes prefixes matching $delete
from the elements, not necessarily whole elements.
Update
To really remove an exact item, you need to walk through the array, comparing the target to each element, and using unset
to delete an exact match.
array=(pluto pippo bob)
delete=(pippo)
for target in "${delete[@]}"; do
for i in "${!array[@]}"; do
if [[ ${array[i]} = $target ]]; then
unset 'array[i]'
fi
done
done
Note that if you do this, and one or more elements is removed, the indices will no longer be a continuous sequence of integers.
$ declare -p array
declare -a array=([0]="pluto" [2]="bob")
The simple fact is, arrays were not designed for use as mutable data structures. They are primarily used for storing lists of items in a single variable without needing to waste a character as a delimiter (e.g., to store a list of strings which can contain whitespace).
If gaps are a problem, then you need to rebuild the array to fill the gaps:
for i in "${!array[@]}"; do
new_array+=( "${array[i]}" )
done
array=("${new_array[@]}")
unset new_array