test -v difference between bash 5.1 and 5.2
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
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
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
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
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
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
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
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
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/