Date:        Wed, 9 Jul 2025 14:00:46 -0400
    From:        Greg Wooledge <g...@wooledge.org>
    Message-ID:  <20250709180045.ga28...@wooledge.org>

  | If that's true, then I don't understand why these two commands give
  | different results:
  |
  |     (( hash[\$key]++ ))
  |     let "hash[\$key]++"
  |
  | hobbit:~$ echo "$BASH_VERSION"
  | 5.3.0(1)-release
  | hobbit:~$ unset hash
  | hobbit:~$ declare -A hash; key=\'\]
  | hobbit:~$ (( hash[\$key]++ )); declare -p hash
  | declare -A hash=(["\$key"]="1" )
  | hobbit:~$ let "hash[\$key]++"; declare -p hash
  | declare -A hash=(["\$key"]="1" ["']"]="1" )

Partly that is because the start conditions aren't the same, for the (( ))
test "hash" is unset, but declared to be an assoc array.   For the let
test, hash is already set.

But only partly...

jacaranda$ echo "$BASH_VERSION"
5.3.0(1)-release
jacaranda$ unset hash
jacaranda$ declare -A hash; key=\'\]
jacaranda$ let "hash[\$key]++"; declare -p hash
declare -A hash=(["']"]="1" )

So it is still different, just different different.

And for this, the (( )) version is clearly correct, the '\' that
is inserted before the $ in a string which is (as Chet said) treated
as double quoted, prevents the '$key' from being a variable reference,
and instead makes it be just the 4 characters '$' 'k' 'e' 'y' (and in
which "declare -p" needs to similarly escape the '$' for correctness).

jacaranda$ unset hash
jacaranda$ declare -A hash; key=\'\]
jacaranda$ (( hash[$key]++ )); declare -p hash
declare -A hash=(["']"]="1" )

which also looks correct to me (not that I really know, or care,
about associative arrays, or any arrays, in sh programming - poor
addition to the shell IMO (lists would be better)).

Why let isn't producing the same result I will leave it to Chet to explain,
its arg is explicitly double quoted, the \$ in there should mean the same
as it does in the (( )) version.

kre




Reply via email to