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.
