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.