test -v difference between bash 5.1 and 5.2

2023-08-29 Thread Christian Schneider

Hi all,

not sure if this intended or not, but in bash 5.2-p15 one of our scripts 
is broken. it is related to test -v, that checks, if a variable is set 
together with arrays.


I condensed it to following example:
#!/bin/bash

declare -A foo
foo=(["a"]="b" ["c"]="d")
declare -a bar
bar=("a" "b" "c")
declare -a baz
baz=("foo" "bar")
for i in "${baz[@]}" ; do
echo $i
if [ ! -v "$i"[@] ] ; then
echo "$i not set"
fi
done


with bash 5.2-p15 the output of this script is
foo
foo not set
bar

so, it doesn't work with associative arrays.
Instead, with 5.1-p16 the output is
foo
bar

so, in 5.1-p16 test -v with associative array works, but not with 5.2-p15.

I don't know, if this an intended change, so please can you take a look?
If it is intended, can you please explain, why this was changed, and if 
there is an alternative for associative arrays?


BR, Christian

--
-
RADIODATA GmbH
Newtonstr. 18
12489 Berlin
Germany

Homepage:  www.radiodata.biz

USt_IdNr.: DE 195663499
WEEE-Reg.-Nr.: DE 63967380

Sitz der Gesellschaft: Berlin
Registergericht:   Amtsgericht Charlottenburg HRB  Nr.: 67865
Geschäftsführer:   Hans-Joachim Langermann, Malte Langermann



Re: test -v difference between bash 5.1 and 5.2

2023-08-29 Thread Chet Ramey

On 8/29/23 10:32 AM, Christian Schneider wrote:

Hi all,

not sure if this intended or not, but in bash 5.2-p15 one of our scripts is 
broken. it is related to test -v, that checks, if a variable is set 
together with arrays.


Yes. Bash-5.2 allows test -v assoc[@] to test whether an associative array
has key `@' set. There was no way to do this in bash-5.1.

If you want to check whether an array variable is set, you can check
whether it has any set elements:

(( ${#assoc[@]} > 0 ))

which will work on bash-5.1 and bash-5.2.

If you set the shell compatibility level to 51, you can get the bash-5.1
behavior on bash-5.2. This is the relevant portion of description of
`compat51' from the bash info manual:

* 'test -v', when given an argument of 'A[@]', where A is an
  existing associative array, will return true if the array has
  any set elements.  Bash-5.2 will look for and report on a key
  named '@'

There was a long discussion about this as part of a bigger 2021 thread
about how bash expanded associative array subscripts, starting at:

https://lists.gnu.org/archive/html/bug-bash/2021-04/msg00058.html

--
``The lyf so short, the craft so long to lerne.'' - Chaucer
 ``Ars longa, vita brevis'' - Hippocrates
Chet Ramey, UTech, CWRUc...@case.eduhttp://tiswww.cwru.edu/~chet/




Re: test -v difference between bash 5.1 and 5.2

2023-08-29 Thread Kerin Millar
Hi,

On Tue, 29 Aug 2023 16:32:36 +0200
Christian Schneider  wrote:

> Hi all,
> 
> not sure if this intended or not, but in bash 5.2-p15 one of our scripts 
> is broken. it is related to test -v, that checks, if a variable is set 
> together with arrays.
> 
> I condensed it to following example:
> #!/bin/bash
> 
> declare -A foo
> foo=(["a"]="b" ["c"]="d")
> declare -a bar
> bar=("a" "b" "c")
> declare -a baz
> baz=("foo" "bar")
> for i in "${baz[@]}" ; do
>  echo $i
>  if [ ! -v "$i"[@] ] ; then
>  echo "$i not set"
>  fi
> done
> 
> 
> with bash 5.2-p15 the output of this script is
> foo
> foo not set
> bar

It pertains to the following change.

j. Associative array assignment and certain instances of referencing (e.g.,
   `test -v' now allow `@' and `*' to be used as keys.

For now, you have the option of setting the compatibility level to 51.

Incidentally, your code is defective to begin with. That is, it doesn't 
actually prove that an array variable is set, even with 5.1.

$ declare -p BASH_VERSION
declare -- BASH_VERSION="5.1.16(1)-release
$ declare -A map; [[ -v 'map[@]' ]]; echo $?
1

Frankly, the only interface that I would trust for this is declare -p, which is 
a wasteful one; there is no way to instruct the declare builtin to refrain from 
writing out the elements of an array.

-- 
Kerin Millar



Re: test -v difference between bash 5.1 and 5.2

2023-08-29 Thread Chet Ramey

On 8/29/23 11:30 AM, Kerin Millar wrote:

Hi,

On Tue, 29 Aug 2023 16:32:36 +0200
Christian Schneider  wrote:


Hi all,

not sure if this intended or not, but in bash 5.2-p15 one of our scripts
is broken. it is related to test -v, that checks, if a variable is set
together with arrays.

I condensed it to following example:
#!/bin/bash

declare -A foo
foo=(["a"]="b" ["c"]="d")
declare -a bar
bar=("a" "b" "c")
declare -a baz
baz=("foo" "bar")
for i in "${baz[@]}" ; do
  echo $i
  if [ ! -v "$i"[@] ] ; then
  echo "$i not set"
  fi
done


with bash 5.2-p15 the output of this script is
foo
foo not set
bar


It pertains to the following change.

j. Associative array assignment and certain instances of referencing (e.g.,
`test -v' now allow `@' and `*' to be used as keys.

For now, you have the option of setting the compatibility level to 51.

Incidentally, your code is defective to begin with. That is, it doesn't 
actually prove that an array variable is set, even with 5.1.

$ declare -p BASH_VERSION
declare -- BASH_VERSION="5.1.16(1)-release
$ declare -A map; [[ -v 'map[@]' ]]; echo $?
1


That isn't set; you have to assign a value to set a variable. For instance,
`export foo' does not result in `foo' being set. What he's really
interested in is whether the array has any set elements.

--
``The lyf so short, the craft so long to lerne.'' - Chaucer
 ``Ars longa, vita brevis'' - Hippocrates
Chet Ramey, UTech, CWRUc...@case.eduhttp://tiswww.cwru.edu/~chet/




Re: test -v difference between bash 5.1 and 5.2

2023-08-29 Thread Kerin Millar
On Tue, 29 Aug 2023 11:24:43 -0400
Chet Ramey  wrote:

> If you want to check whether an array variable is set, you can check
> whether it has any set elements:
> 
> (( ${#assoc[@]} > 0 ))

This doesn't check whether an "array variable is set".

Not only that, but the test will be true in the case that assoc has been 
defined as a variable that is not an array.

$ unset -v assoc; assoc=; (( ${#assoc[@]} > 0 )); echo $?
0

-- 
Kerin Millar



Re: test -v difference between bash 5.1 and 5.2

2023-08-29 Thread Kerin Millar
On Tue, 29 Aug 2023 11:34:21 -0400
Chet Ramey  wrote:

> On 8/29/23 11:30 AM, Kerin Millar wrote:
> > Hi,
> > 
> > On Tue, 29 Aug 2023 16:32:36 +0200
> > Christian Schneider  wrote:
> > 
> >> Hi all,
> >>
> >> not sure if this intended or not, but in bash 5.2-p15 one of our scripts
> >> is broken. it is related to test -v, that checks, if a variable is set
> >> together with arrays.
> >>
> >> I condensed it to following example:
> >> #!/bin/bash
> >>
> >> declare -A foo
> >> foo=(["a"]="b" ["c"]="d")
> >> declare -a bar
> >> bar=("a" "b" "c")
> >> declare -a baz
> >> baz=("foo" "bar")
> >> for i in "${baz[@]}" ; do
> >>   echo $i
> >>   if [ ! -v "$i"[@] ] ; then
> >>   echo "$i not set"
> >>   fi
> >> done
> >> 
> >>
> >> with bash 5.2-p15 the output of this script is
> >> foo
> >> foo not set
> >> bar
> > 
> > It pertains to the following change.
> > 
> > j. Associative array assignment and certain instances of referencing (e.g.,
> > `test -v' now allow `@' and `*' to be used as keys.
> > 
> > For now, you have the option of setting the compatibility level to 51.
> > 
> > Incidentally, your code is defective to begin with. That is, it doesn't 
> > actually prove that an array variable is set, even with 5.1.
> > 
> > $ declare -p BASH_VERSION
> > declare -- BASH_VERSION="5.1.16(1)-release
> > $ declare -A map; [[ -v 'map[@]' ]]; echo $?
> > 1
> 
> That isn't set; you have to assign a value to set a variable. For instance,

Fair enough.

> `export foo' does not result in `foo' being set. What he's really
> interested in is whether the array has any set elements.

Yes, hopefully.

-- 
Kerin Millar



Re: test -v difference between bash 5.1 and 5.2

2023-08-29 Thread Chet Ramey

On 8/29/23 11:38 AM, Kerin Millar wrote:

On Tue, 29 Aug 2023 11:24:43 -0400
Chet Ramey  wrote:


If you want to check whether an array variable is set, you can check
whether it has any set elements:

(( ${#assoc[@]} > 0 ))


This doesn't check whether an "array variable is set".


It checks whether there are any set elements. You have to assign a value
to set a variable.


Not only that, but the test will be true in the case that assoc has been 
defined as a variable that is not an array.


One hopes that the shell programmer knows what variable types he's
using, and uses the appropriate constructs.

--
``The lyf so short, the craft so long to lerne.'' - Chaucer
 ``Ars longa, vita brevis'' - Hippocrates
Chet Ramey, UTech, CWRUc...@case.eduhttp://tiswww.cwru.edu/~chet/




Re: test -v difference between bash 5.1 and 5.2

2023-08-29 Thread Kerin Millar
On Tue, 29 Aug 2023 11:44:13 -0400
Chet Ramey  wrote:

> On 8/29/23 11:38 AM, Kerin Millar wrote:
> > On Tue, 29 Aug 2023 11:24:43 -0400
> > Chet Ramey  wrote:
> > 
> >> If you want to check whether an array variable is set, you can check
> >> whether it has any set elements:
> >>
> >> (( ${#assoc[@]} > 0 ))
> > 
> > This doesn't check whether an "array variable is set".
> 
> It checks whether there are any set elements. You have to assign a value
> to set a variable.

I conflated the property of being set with that of being declared. Sorry about 
that. So, what I really meant to say was that the existing test does not prove 
that it's declared. I initially thought that Christian might be concerned with 
that distinction, but do hope it's not the case.

> 
> > Not only that, but the test will be true in the case that assoc has been 
> > defined as a variable that is not an array.
> 
> One hopes that the shell programmer knows what variable types he's
> using, and uses the appropriate constructs.

Some elect to source shell code masquerading as configuration data (or are 
using programs that elect to do so). Otherwise, yes, definitely.

-- 
Kerin Millar



Re: test -v difference between bash 5.1 and 5.2

2023-08-29 Thread Chet Ramey

On 8/29/23 11:56 AM, Kerin Millar wrote:


One hopes that the shell programmer knows what variable types he's
using, and uses the appropriate constructs.


Some elect to source shell code masquerading as configuration data (or are 
using programs that elect to do so). Otherwise, yes, definitely.


If you find yourself needing to know whether a variable is an associative
array, an indexed array, or a scalar, check the output of the @a variable
transformation.

--
``The lyf so short, the craft so long to lerne.'' - Chaucer
 ``Ars longa, vita brevis'' - Hippocrates
Chet Ramey, UTech, CWRUc...@case.eduhttp://tiswww.cwru.edu/~chet/