[Top][All Lists]

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

Re: Changing the way bash expands associative array subscripts

From: Greg Wooledge
Subject: Re: Changing the way bash expands associative array subscripts
Date: Tue, 6 Apr 2021 13:42:20 -0400

On Wed, Apr 07, 2021 at 01:46:27AM +0900, Koichi Murase wrote:
> I remember there was some discussion in the bug-bash list on the
> behavior of `test -v a[@]' which actually tests whether the array `a'
> has at least one element.

> It cannot be replaced by `test -v a' because
> `a' implies `a[0]' here.

Both of those behaviors look wrong to me, but I seem to be in the

> But if I correctly understand it, `test -v
> a[@]' can be replaced by `((${#a[@]}))'. Should any scripts relying on
> `test -v a[@]' to test the array elements also be changed?

I would never write a script like that, but it doesn't seem necessary
to break any scripts that are using it.  It's not a complete disaster
that destroys your entire array when the user types '@', so I could live
with it sticking around.

Anyone using test -v 'a[$key]' as an attempt to determine whether a key
exists may get the wrong answer when the key is * or @.

And for the record, 'a[@]' still needs to be quoted.

When you put all of these issues together, it's clear that associative
arrays in bash have *deep* flaws, and require some workarounds to use

1) The empty string cannot be used as an index, under any circumstances.

2) The indices * and @ may cause surprising behaviors in several different

Both of these can be worked around by adopting the old "put an x in front
of it" hack from the days of yore.  Ironic, isn't it, how some things
never die.

3) Expressions like a[$key] must be single-quoted in some contexts, or
   you get surprising behaviors.

4) Expressions like a[$key] must be backslash-protected in some other
   contexts, or you get surprising behaviors.

Just ugh.

> $ iref1=a[@]; printf '<%s>' "${!iref1}"; echo
> <y><x>
> $ key=@; iref2=a[$key]; printf '<%s>' "${!iref2}"; echo
> <y><x>    # <-- unexpected

This test is flawed; the $key is expanded during the assignment to iref2.

unicorn:~$ declare -A a=(['@']=x [1]=y)
unicorn:~$ key=@; iref2='a[$key]'; printf '<%s>' "${!iref2}"; echo

That said, the fact that you can put 'a[@]' in an indirect variable and
get an array expansion out of "${!x}" is completely repulsive to me.  In
the past, I have asked whether this is actually working as intended,
and Chet's answer simply confused me, but near as I can tell, he seems
to think it should continue doing this.  So I won't say anything more
about it.

reply via email to

[Prev in Thread] Current Thread [Next in Thread]