[Top][All Lists]

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

Changing the way bash expands associative array subscripts

From: Chet Ramey
Subject: Changing the way bash expands associative array subscripts
Date: Mon, 15 Mar 2021 20:12:00 -0400
User-agent: Mozilla/5.0 (Macintosh; Intel Mac OS X 10.15; rv:78.0) Gecko/20100101 Thunderbird/78.8.1

I'm kicking around a change to associative array subscript expansion that
would basically force the equivalent of `assoc_expand_once' on all the
time, with additional changes to prevent unwanted double expansion in an
arithmetic expression context. The option would still exist, and still be
settable and unsettable, but have little to no effect in default mode.

For instance,

declare -A assoc
key='x],b[$(echo uname >&2)'

(( assoc[$key]++ ))
declare -p assoc

would display

declare -A assoc=(["x],b[\$(echo uname >&2)"]="1" )

This is relatively straightforward to explain to people.

It's also pretty straightforward to do for internal shell commands and
expansions: things like expression evaluation as part of word expansion,
arithmetic commands, conditional commands, and so on.

The issue lies with shell builtins. Builtin commands have to undergo the
full set of shell expansions (yes, with the caveat about declaration
commands that I explained a couple of days ago). That's not a problem to
explain, but there are a number of workarounds that people have developed
over time to quote their way out of the double expansions that can occur,
and those would be invalidated by a change to force a single expansion
everywhere it's possible. Of course, you can always force multiple
expansion using `eval' or similar.

This means that, given the following script,

declare -A a
key='$(echo foo)'

# never worked
unset -v a[$key]
declare -p a

# unsets element with key $key
unset -v a['$key']
declare -p a

# unsets element with key $(echo foo)
unset -v a["$key"]
declare -p a

# unsets element with key foo
eval unset -v a\["$key"\]
declare -p a

you'll get this output:

example: line 8: unset: `a[$(echo': not a valid identifier
example: line 8: unset: `foo)]': not a valid identifier
declare -A a=(["\$(echo foo)"]="1" ["\$key"]="2" [foo]="3" )
declare -A a=(["\$(echo foo)"]="1" [foo]="3" )
declare -A a=([foo]="3" )
declare -A a=()

Put aside for a minute the fact that I didn't quote the brackets. It's
not important to the narrative.

Obviously, this isn't backwards compatible. Just as obviously, I claim,
it's more desirable behavior. I would have to make the old behavior,
including the previous behavior of `assoc_expand_once', dependent on
BASH_COMPAT=51. But I think it's better behavior, fixes a number of
shortcomings in the current implementation, and sets things up better
for future changes.

What do folks think?


``The lyf so short, the craft so long to lerne.'' - Chaucer
                 ``Ars longa, vita brevis'' - Hippocrates
Chet Ramey, UTech, CWRU

reply via email to

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