help-bash
[Top][All Lists]
Advanced

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

Re: question about, why does my code work in normal bash but not bash de


From: Greg Wooledge
Subject: Re: question about, why does my code work in normal bash but not bash devel
Date: Mon, 25 Apr 2022 12:08:59 -0400

On Mon, Apr 25, 2022 at 05:47:38PM +0200, alex ratchev wrote:
> On Mon, Apr 25, 2022, 16:02 Chet Ramey <chet.ramey@case.edu> wrote:
> > On 4/24/22 5:08 PM, alex ratchev wrote:
> >   mkmenu() {
> > declare var
> > menustr=
> >    for var in $( compgen -A function ) ; do
> >   [[ -v help[\$var] ]] ||
> > continue
> > menustr+="$var <- ${help[$var]}"$'\n'
> >    done
> >   }

> > k. Bash attempts to expand indexed array subscripts only once when
> > executing
> >     shell constructs and word expansions.
> >
> > though it should say `indexed and associative'. In bash-5.2, bash tries to
> > behave as if `assoc_expand_once' is set when expanding associative array
> > subscripts for shell compound commands and parameter expansions. You can
> > set BASH_COMPAT=51 to get the behavior you want.
> 
> that means..dont \ the $var to make it work ?
> i barley understand the english else

You're not the only one who finds the whole situation massively
confusing.  This is related to pitfall #61 on my page:

<https://mywiki.wooledge.org/BashPitfalls#pf61>

    61. [[ -v hash[$key] ]]

    Here, hash is an associative array. This construct fails because
    $key is expanded before the array subscript evaluation, and then the
    whole array plus expanded index is evaluated in a second pass. It will
    appear to work for simple keys, but it will fail for keys containing
    quotes, closing square brackets, etc. Even worse, it introduces a
    CodeInjection if the $key contains CommandSubstitution syntax.

    The same problem applies to the test and [ commands, as well as any
    use of an associative array element in an arithmetic context.

    Newer versions of bash (5.0 and higher) have a assoc_expand_once
    option which will suppress the multiple evaluations. Another choice
    is to single-quote the entire argument:

    [[ -v 'hash[$key]' ]]

    This has the advantage of working in older versions of bash as well
    as newer versions.

I suppose I'll have to edit the page again once bash 5.2 comes out.  It
appears that as of bash 5.2 there will be NO safe way to do it that
isn't tied to a specific bash version.  If you use the single quotes,
it works in bash 4.0 through 5.1, and fails in bash 5.2.  If you omit
the single quotes, it works in bash 5.2, and fails catastrophically (e.g.
code injection) in 4.0 through 5.1.

For whatever it's worth, I don't do abstract set data structures this
way.  What you're doing (it appears) is:

   hash is an associative array which represents an abstract set.

   If $key is present in hash, regardless of its value, then $key is
   present in the abstract set.

   If $key is not present in hash, it is not present in the abstract
   set.

   Use [[ -v something ]] to determine whether the $key is present in
   the hash.

Here's how I've been doing it:

   hash is an associative array which represents an abstract set.

   If the expansion of hash[$key] is a non-empty string, then $key is
   present in the abstract set.

   If the expansion of hash[$key] is an empty string, then $key is
   not present in the abstract set.

   Use [[ ${hash[$key]} ]] to determine whether the $key is present
   in the hash.

For whatever reason, [[ -v hash[$key] ]] triggers double expansions and
code injections, but [[ ${hash[$key]} ]] does not.  Will it blow up if
you use set -u?  Maybe!  Guess what... I don't use set -u.

Other people may feel free to argue about how things should/shouldn't
work, but I prefer to focus on what *does* work, and what doesn't.



reply via email to

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