Search code examples
arraysbashelementunset

Unable to delete array element using 'read -n 1' character as array index


I'm trying to dynamically delete elements from an array in bash based on a script argument of the form '123' where each single digit number in the argument is assumed to be an index of the array which should be removed.

#!/bin/bash
# Doesn't delete an element.
ARRAY=(a b c)
while getopts ":a:" opt; do # run e.g. 'thisscript.h -a 0'
    case $opt in
        a)
            echo -n $OPTARG |\
                while read -n 1 c; do
                    unset ARRAY[$c]
                done
                ;;
    esac
done
echo ${ARRAY[@]}
# Deletes an element successfully.
ARRAY=(a b c)
unset ARRAY[0]
echo ${ARRAY[@]}
# Deletes an element successfully.
ARRAY=(a b c)
n=0
unset ARRAY[$n]
echo ${ARRAY[@]}

Write this to e.g. tmp.sh file, chmod +x tmp.sh to make executable, then run 'tmp.sh -a 0'.

Why doesn't the first array element deletion method work, and how can I make it work within the 'read -n 1' context?


Solution

  • The problem is the PIPED while-read loop which runs as a subshell. Therefore, the unset occurs in a subshell and disappears when the subshell exits. That's why there is no effect on the array variable.

    This problem is described in Section 20.2. Redirecting Code Blocks of the Advanced Bash-Scripting Guide.

    Here is one workaround, using process substitution instead of a pipe.

    while read -n 1 c; do
        unset ARRAY[$c]
    done < <(echo -n $OPTARG)