Home > OS >  Bash shift changes expected value of associative array
Bash shift changes expected value of associative array

Time:08-09

I made a simple script, that matches the positional arguments starting with dash, and saves them into an associative array.

declare -A opts

for i; do
  [[ "$i" =~ - ]] && opts[$i]=1
done

shift "${#opts[*]}"

echo "opts: ${opts[*]}"
echo "!opts: ${!opts[-d]}"
echo "Query: $*"

For the call ./script -d hello world the output is:

opts: 1
!opts: hello
Query: hello world

Which is unexpected, since the key of ${!opts[-d]} is supposed to be -d itself if defined. This behavior happens because of the shift command, when it is removed from the code, the output is as expected:

opts: 1
!opts: -d
Query: -d hello world

Why does shift interfere with the created associative array?

CodePudding user response:

The associative array isn't being changed; you can verify this by putting a declare -p opts after the shift, which will give

declare -A opts=([-d]="1" )

The problem: ${!opts[-d]} doesn't do what you seem to expect. First, opts[-d] is looked up, which is the value 1. Then the ! means that's used as the name of a variable to substitute - so it's effectively the same as $1, which, after the shift, is hello.

If you want to print out all the keys of the associative array, use ${!opts[@]}. The leading ! has two different meanings in bash paramater expansion depending on if used with an array with @ or * in the brackets, or an index/normal variables.

  • Related