bug-bash
[Top][All Lists]
Advanced

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

Re: Indices of array variables are sometimes considered unset (or just d


From: Great Big Dot
Subject: Re: Indices of array variables are sometimes considered unset (or just display an error).
Date: Mon, 5 Nov 2018 20:44:44 -0500

> On Mon, Nov 5, 2018 at 4:56 PM Great Big Dot <greatbigdot@gmail.com>
wrote:
> [... A]ccessing the index list of multiple-element arrays
> fails when you append the unset expansion. With single-element
> arrays, it fails iff the element in question contains any special
> characters or whitespace, and thinks the array is unset otherwise.
> (Further testing shows that a value of the empty string also throws
> an error.) Finally, empty arrays are also considered unset[...]

Oops, just realized what's causing this. I guess it isn't necessarily a
bug? Debatable, I guess.

What's actually happening here is that the *indirection* expansion
"${!foo}", and not the *indices* expansion "${!foo[@]}", is what is being
preformed on something like "${!array[@]-}". Both expansions, while
unrelated, happen to use the same syntax, with the exception that
indirections apply to normal variables and index expansions apply to array
variables. For some reason, adding on the "${foo-default}" expansion causes
the former to be used instead of the latter. This can be seen here:

    $ array=(foo)
    $ printf -- '%s\n' "${!foo[@]-unset}"
    unset
    $ foo='hello world'
    $ printf -- '%s\n' "${!foo[@]-unset}"
    hello world

So first the array is expanded, and then it's treated as a redirection, and
then the unset part kicks in if the array's value isn't an extant variable
name. This explains all the observations I made.

I still think it makes more sense if the "!" in "${!array[@]}" triggered
index expansion instead. At the very least, surely it should be one of
those expansion combinations that just isn't allowed, like
"${#foo[@]-default}" (actually, why is that disallowed?). Anyways, I don't
really see the point of the current behavior.

> This pattern of behavior is apparently unaffected by changes to IFS[...]

Upon further examination, and in light of the above realization, this
actually isn't true. In particular, iff the first character of IFS is
alphanumeric or an underscore (or if IFS is the empty string), and if you
use the "${array[*]}" form instead, then the expansion doesn't throw an
error when the array contains more than one element. E.g.:

    $ array=(foo bar)
    $ printf -- '%s\n' "${!array[*]-Warning: unset}"
    bash: foo bar: bad substitution
    $ IFS='_'
    $ printf -- '%s\n' "${!array[*]-Warning: unset}"
    Warning: unset
    $ foo_bar='Beto2018'
    $ printf -- '%s\n' "${!array[*]-Warning: unset}"
    Beto2018
    $ IFS=''
    $ printf -- '%s\n' "${!array[*]-Warning: unset}"
    Warning: unset
    $ foobar='Hello, world'
    $ printf -- '%s\n' "${!array[*]-Warning: unset}"
    Hello, world

Though I understand it now, the above behavior doesn't seem especially
motivated to me. I mean, the variables that end up getting expanded don't
actually have their names stored anywhere, yet the indirection points to
them.

Is there a good reason for treating "${!array[@]-}" and "${!array[*]-}"
like indirections instead of index expansions (or just throwing an error)?


reply via email to

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