Search code examples
arraysbashvariables

Remove an element from a Bash array


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?


Solution

  • 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 first match of $delete from each of 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