need ability to tell if array is associative or not - bug?
Good day list - There seems to be no way of testing if an array variable is associative or not , yet attempting to make associative assigments to a normal array results in a syntax error . I have something like: declare -xr TYPE_ARRAY=0 TYPE_ASSOC=1 function f() { declare -n an_array=$1; local type=$2; case $type in $TYPE_ASSOC) an_array['some_value']=1; }
Re: need ability to tell if array is associative or not - bug?
On Fri, Aug 29, 2014 at 03:07:40PM +0100, Jason Vas Dias wrote: > There seems to be no way of testing if an array variable is associative or not $ unset a b; declare -A a; a[1]=foo; b=(an array); declare -p a b declare -A a='([1]="foo" )' declare -a b='([0]="an" [1]="array")'
Re: need ability to tell if array is associative or not - bug?
Sorry, mailer sent previous mail before I was ready. Reposting. Good day list - There seems to be no way of testing if an array variable is associative or not , I have something like: declare -xr TYPE_ARRAY=0 TYPE_ASSOC=1 function f() { declare -n an_array=$1; local type=$2; case $type in $TYPE_ASSOC) an_array['some_value']=1; ;; $TYPE_ARRAY) an_array[0]=1; esac } Now, if I call : declare -a my_array(); f my_array $TYPE_ASSOC; I'll end up with no 'some_value' subscript in array. It would be great if bash could provide some '-A' conditional expression operator to test if a variable is an associative array or not . Or perhaps 'declare -A identifier' could return non-zero if 'identifier' was not previously defined as an associative array, as declare -F does for functions ? Or is there some way to test if a variable is an associative array or not? Thanks & Regards, Jason On 8/29/14, Jason Vas Dias wrote: > Good day list - > > There seems to be no way of testing if an array variable is associative or > not , > yet attempting to make associative assigments to a normal array results in > a > syntax error . > > I have something like: > > declare -xr TYPE_ARRAY=0 TYPE_ASSOC=1 > function f() > { declare -n an_array=$1; >local type=$2; >case $type in > $TYPE_ASSOC) > an_array['some_value']=1; > > > } >
Re: need ability to tell if array is associative or not - bug?
On 8/29/14, 10:21 AM, Jason Vas Dias wrote: > Sorry, mailer sent previous mail before I was ready. Reposting. > > Good day list - > > There seems to be no way of testing if an array variable is associative or > not , > > I have something like: > > declare -xr TYPE_ARRAY=0 TYPE_ASSOC=1 > function f() > { declare -n an_array=$1; >local type=$2; >case $type in > $TYPE_ASSOC) > an_array['some_value']=1; > ;; > $TYPE_ARRAY) > an_array[0]=1; >esac >} > > Now, if I call : >declare -a my_array(); f my_array $TYPE_ASSOC; Syntax errors aside, isn't this pretty clearly a programming error? I mean, you've passed the wrong type. I can maybe see the value in being able to write code that is able to catch these kinds of errors without parsing the output of `declare', but it's a big stretch to call this a bug. > I'll end up with no 'some_value' subscript in array. > > It would be great if bash could provide some '-A' conditional > expression operator > to test if a variable is an associative array or not . > Or perhaps 'declare -A identifier' could return non-zero if > 'identifier' was not previously defined as an associative array, as > declare -F does for functions ? It already does that when you attempt to convert an indexed array to an associative array, and prints an error message to drive the point home. The problem with doing it in the general case is that the semantics of converting a scalar to an associative array are already well-defined. Chet -- ``The lyf so short, the craft so long to lerne.'' - Chaucer ``Ars longa, vita brevis'' - Hippocrates Chet Ramey, ITS, CWRUc...@case.eduhttp://cnswww.cns.cwru.edu/~chet/
Re: need ability to tell if array is associative or not - bug?
Actually, this appears to be a bit more involved. What I was actually trying to work out was the bash error that occurs with : $( function f() { local an_array=$1; local value='1.0'; local v=value; local ev='['"'"'value'"'"']='"'""${!v}""'"; eval ${an_array}='('"$ev"')'; } declare -a my_array; set -x; f my_array; ) + f my_array + local an_array=my_array + local value=1.0 + local v=value + local 'ev=['\''value'\'']='\''1.0'\''' + eval 'my_array=(['\''value'\'']='\''1.0'\'')' ++ my_array=(['value']='1.0') bash: 1.0: syntax error: invalid arithmetic operator (error token is ".0") This error does not happen if the array was originally declared associative: $ ( function f() { local an_array=$1; local value='1.0'; local v=value; local ev='['"'"'value'"'"']='"'""${!v}""'"; eval ${an_array}='('"$ev"')'; }; declare -A my_array; set -x; f my_array ) + f my_array + local an_array=my_array + local value=1.0 + local v=value + local 'ev=['\''value'\'']='\''1.0'\''' + eval 'my_array=(['\''value'\'']='\''1.0'\'')' ++ my_array=(['value']='1.0') Nor does the error happen if indirect expansion is not used: $ ( function f() { local an_array=$1; local value='1.0'; local v=$value; local ev='['"'"'value'"'"']='"'""$v""'"; eval ${an_array}='('"$ev"')'; }; declare -A my_array; set -x; f my_array ) + f my_array + local an_array=my_array + local value=1.0 + local v=1.0 + local 'ev=['\''value'\'']='\''1.0'\''' + eval 'my_array=(['\''value'\'']='\''1.0'\'')' ++ my_array=(['value']='1.0') $ So I was wondering if there is any way to determine if an array was originally declared associative or not. But it appears that there is a bash bug here that is triggered only if the array was originally declared not associative and an indirect expansion is involved in setting an array member. The end result expression being evaluated: ++ my_array=(['value']='1.0') should never involve an arithmetic expression, and should be valid regardless if the array is associative or not . Any ideas what might be going on here ? Thanks in advance, Jason On 8/29/14, Jason Vas Dias wrote: > Sorry, mailer sent previous mail before I was ready. Reposting. > > Good day list - > > There seems to be no way of testing if an array variable is associative or > not , > > I have something like: > > declare -xr TYPE_ARRAY=0 TYPE_ASSOC=1 > function f() > { declare -n an_array=$1; >local type=$2; >case $type in > $TYPE_ASSOC) > an_array['some_value']=1; > ;; > $TYPE_ARRAY) > an_array[0]=1; >esac >} > > Now, if I call : >declare -a my_array(); f my_array $TYPE_ASSOC; > I'll end up with no 'some_value' subscript in array. > > It would be great if bash could provide some '-A' conditional > expression operator > to test if a variable is an associative array or not . > Or perhaps 'declare -A identifier' could return non-zero if > 'identifier' was not previously defined as an associative array, as > declare -F does for functions ? > Or is there some way to test if a variable is an associative array or not? > > Thanks & Regards, > Jason > > > On 8/29/14, Jason Vas Dias wrote: >> Good day list - >> >> There seems to be no way of testing if an array variable is associative >> or >> not , >> yet attempting to make associative assigments to a normal array results >> in >> a >> syntax error . >> >> I have something like: >> >> declare -xr TYPE_ARRAY=0 TYPE_ASSOC=1 >> function f() >> { declare -n an_array=$1; >>local type=$2; >>case $type in >> $TYPE_ASSOC) >> an_array['some_value']=1; >> >> >> } >> >
Re: need ability to tell if array is associative or not - bug?
On Fri, Aug 29, 2014 at 04:45:30PM +0100, Jason Vas Dias wrote: > local value='1.0'; > The end result expression being evaluated: > ++ my_array=(['value']='1.0') > should never involve an arithmetic expression, > and should be valid regardless if the array is > associative or not . Your index is "value". In a non-associative array, the index is evaluated in a math context. In a math context, a thing that CAN be treated as a variable name IS treated as a variable name, and this treatment is recursive. So you are using an index of 1.0, and this causes the error message.
Re: need ability to tell if array is associative or not - bug?
Sorry - forget the bit about indirect expansion - the error only occurs if the array is originally declared not associative : $ ( function f() { local an_array=$1; local value='1.0'; local ev='['"'"'value'"'"']='"'""$value""'"; eval ${an_array}='('"$ev"')'; }; declare -a my_array; set -x; f my_array ) + f my_array + local an_array=my_array + local value=1.0 + local 'ev=['\''value'\'']='\''1.0'\''' + eval 'my_array=(['\''value'\'']='\''1.0'\'')' ++ my_array=(['value']='1.0') bash: 1.0: syntax error: invalid arithmetic operator (error token is ".0") $ ( function f() { local an_array=$1; local value='1.0'; local ev='['"'"'value'"'"']='"'""$value""'"; eval ${an_array}='('"$ev"')'; }; declare -A my_array; set -x; f my_array ) + f my_array + local an_array=my_array + local value=1.0 + local 'ev=['\''value'\'']='\''1.0'\''' + eval 'my_array=(['\''value'\'']='\''1.0'\'')' ++ my_array=(['value']='1.0') $ (no error) . And just evaluating : $ ( declare -a my_array; my_array=(['value']='1.0') ) gives no error either, but there is no 'value' subscript. On 8/29/14, Jason Vas Dias wrote: > Actually, this appears to be a bit more involved. > What I was actually trying to work out was > the bash error that occurs with : > > $( function f() > { > local an_array=$1; > local value='1.0'; > local v=value; > local ev='['"'"'value'"'"']='"'""${!v}""'"; > eval ${an_array}='('"$ev"')'; > } > declare -a my_array; > set -x; f my_array; > ) > + f my_array > + local an_array=my_array > + local value=1.0 > + local v=value > + local 'ev=['\''value'\'']='\''1.0'\''' > + eval 'my_array=(['\''value'\'']='\''1.0'\'')' > ++ my_array=(['value']='1.0') > bash: 1.0: syntax error: invalid arithmetic operator (error token is ".0") > > This error does not happen if the array was originally declared > associative: > > $ ( function f() { local an_array=$1; local value='1.0'; > local v=value; local ev='['"'"'value'"'"']='"'""${!v}""'"; > eval ${an_array}='('"$ev"')'; }; > declare -A my_array; set -x; f my_array ) > + f my_array > + local an_array=my_array > + local value=1.0 > + local v=value > + local 'ev=['\''value'\'']='\''1.0'\''' > + eval 'my_array=(['\''value'\'']='\''1.0'\'')' > ++ my_array=(['value']='1.0') > > Nor does the error happen if indirect expansion is not used: > > $ ( function f() { local an_array=$1; local value='1.0'; > local v=$value; > local ev='['"'"'value'"'"']='"'""$v""'"; > eval ${an_array}='('"$ev"')'; }; declare -A my_array; set -x; f > my_array ) > + f my_array > + local an_array=my_array > + local value=1.0 > + local v=1.0 > + local 'ev=['\''value'\'']='\''1.0'\''' > + eval 'my_array=(['\''value'\'']='\''1.0'\'')' > ++ my_array=(['value']='1.0') > $ > > So I was wondering if there is any way to determine if an array was > originally > declared associative or not. > > But it appears that there is a bash bug here that is triggered only if the > array was originally declared not associative and an indirect expansion > is involved in setting an array member. > > The end result expression being evaluated: > ++ my_array=(['value']='1.0') > should never involve an arithmetic expression, > and should be valid regardless if the array is > associative or not . > > Any ideas what might be going on here ? > > Thanks in advance, > Jason > > On 8/29/14, Jason Vas Dias wrote: >> Sorry, mailer sent previous mail before I was ready. Reposting. >> >> Good day list - >> >> There seems to be no way of testing if an array variable is associative >> or >> not , >> >> I have something like: >> >> declare -xr TYPE_ARRAY=0 TYPE_ASSOC=1 >> function f() >> { declare -n an_array=$1; >>local type=$2; >>case $type in >> $TYPE_ASSOC) >> an_array['some_value']=1; >> ;; >> $TYPE_ARRAY) >> an_array[0]=1; >>esac >>} >> >> Now, if I call : >>declare -a my_array(); f my_array $TYPE_ASSOC; >> I'll end up with no 'some_value' subscript in array. >> >> It would be great if bash could provide some '-A' conditional >> expression operator >> to test if a variable is an associative array or not . >> Or perhaps 'declare -A identifier' could return non-zero if >> 'identifier' was not previously defined as an associative array, as >> declare -F does for functions ? >> Or is there some way to test if a variable is an associative array or >> not? >> >> Thanks & Regards, >> Jason >> >> >> On 8/29/14, Jason Vas Dias wrote: >>> Good day list - >>> >>> There seems to be no way of testing if an array variable is associative >>> or >>> not , >>> yet attempting to make associative assigments to a normal array results >>> in >>> a >>> syntax error . >>> >>> I have something like: >>> >>> declare -xr TYPE_ARRAY=0 TYPE_ASSOC=1 >>> function f() >>> { declare -n an_array=$1; >>>local type=$2; >>>case $type in >>> $TYPE_ASSOC) >>>
Re: need ability to tell if array is associative or not - bug?
On 8/29/14, 11:45 AM, Jason Vas Dias wrote: > Nor does the error happen if indirect expansion is not used: Just to head off a potential question. This is not the same as the first example, since my_array is declared as an associative array. > $ ( function f() { local an_array=$1; local value='1.0'; > local v=$value; > local ev='['"'"'value'"'"']='"'""$v""'"; > eval ${an_array}='('"$ev"')'; }; declare -A my_array; set -x; f my_array > ) ^^^ ||| > + f my_array > + local an_array=my_array > + local value=1.0 > + local v=1.0 > + local 'ev=['\''value'\'']='\''1.0'\''' > + eval 'my_array=(['\''value'\'']='\''1.0'\'')' > ++ my_array=(['value']='1.0') > $ -- ``The lyf so short, the craft so long to lerne.'' - Chaucer ``Ars longa, vita brevis'' - Hippocrates Chet Ramey, ITS, CWRUc...@case.eduhttp://cnswww.cns.cwru.edu/~chet/
Re: need ability to tell if array is associative or not - bug?
On Fri, Aug 29, 2014 at 05:19:03PM +0100, Jason Vas Dias wrote: > Aha! Yes, that was it . Thank you! > I wouldn't have expected expansion to occur for a name in single quotes. > > I still think it would be nice to have the ability to tell if an array has > been > declared associative or not. What about a 'test -A my_array' operator ? $ unset a b; declare -A a; a[1]=foo; b=(an array); declare -p a b declare -A a='([1]="foo" )' declare -a b='([0]="an" [1]="array")' If you want to mangle that into a test, it would be something like: if [[ $(declare -p a) = declare\ -A* ]]; then I still don't understand what your function is trying to DO, though. Whatever it is, it looks extremely awkward and painful. My advice to anyone who is trying to pass the name of an array as an argument to a function in Bash is usually "Stop! Use a real programming language instead." Even declare -n didn't give us the ability to do this safely. If you insist on doing this, you need to check all the user input before handing it to eval.
Re: minor: "read line" may read several lines if stdin is a tty
2014-08-27 15:35:06 -0400, Chet Ramey: > On 8/27/14, 3:20 PM, Stephane Chazelas wrote: > > > However, one could imagine using bash's read to get data off a > > tty device not in canonical mode (a serial device used as just a > > serial device), or any other non-terminal character device for > > that matter (a "strace bash -c 'read < /dev/urandom'" reveals > > there's an issue there as well), and that would be more of a > > problem. > > > > Again, not a big one (hence the [minor] tag) but still a > > non-POSIX conformance and bash seems to be the only shell with > > the problem (though ksh93 has its own bugs as usual). > > Well, again you have to rely on the system telling you what's happening. > Bash tests whether a file descriptor is seekable using, logically > enough, lseek. If it doesn't return -1/ESPIPE, bash assumes the fd is > seekable. If it does, bash does unbuffered reads. [...] OK, sorry, I hadn't realised /dev/random was seekable (though the seek is a no-op) on Linux. > (If isatty() returns true, bash does assume that read(2) will return > newline-delimited records.) [...] That assumption is only valid (to some extent, because of lnext) if the terminal is in icanon mode though. Cheers, Stephane
nameref bug?
The following is my test scripts and their output. They are very similar, and I do not think they should result in different output. The output I expected from all of them is: v1 v2 But as you can see, only 1 in the following 4 cases does it meet my expectation. In the other 3 cases, the nameref attribute of the variable 'ref' is lost unexpectedly. === script === #!/bin/bash declare -a arr=('dict[k1]' 'dict[k2]') declare -A dict='([k1]=v1 [k2]=v2)' func() { local -i i for ((i=0; i<${#arr[@]}; ++i)); do local -n ref ref=${arr[i]} echo $ref done } func --- output --- v1 v2 === script === #!/bin/bash declare -a arr=('dict[k1]' 'dict[k2]') declare -A dict='([k1]=v1 [k2]=v2)' func() { local -i i local -n ref for ((i=0; i<${#arr[@]}; ++i)); do ref=${arr[i]} echo $ref done } func --- output --- v1 dict[k2] === script === #!/bin/bash declare -a arr=('dict[k1]' 'dict[k2]') declare -A dict='([k1]=v1 [k2]=v2)' declare -i i for ((i=0; i<${#arr[@]}; ++i)); do declare -n ref ref=${arr[i]} echo $ref done --- output --- v1 dict[k2] === script === #!/bin/bash declare -a arr=('dict[k1]' 'dict[k2]') declare -A dict='([k1]=v1 [k2]=v2)' declare -i i declare -n ref for ((i=0; i<${#arr[@]}; ++i)); do ref=${arr[i]} echo $ref done --- output --- v1 dict[k2]
Re: nameref bug?
On Sat, Aug 30, 2014 at 11:19 AM, lolilolicon wrote: > The following is my test scripts and their output. > They are very similar, and I do not think they should result in > different output. > The output I expected from all of them is: > > v1 > v2 > > But as you can see, only 1 in the following 4 cases does it meet my > expectation. In the other 3 cases, the nameref attribute of the variable > 'ref' is lost unexpectedly. It seems to be a namespace / scope problem. Another test script reveals that without assigning ref explicitly, such as using the "for ... in" construct, it behaves as expected. === script === #!/bin/bash declare -a arr=('dict[k1]' 'dict[k2]') declare -A dict='([k1]=v1 [k2]=v2)' declare -n ref for ref in "${arr[@]}"; do echo $ref done ref=${arr[0]} echo $ref ref=${arr[1]} echo $ref --- output --- v1 v2 dict[k1] dict[k2] As you see, once ref is assigned explicitly, or indeed, is assigned for a second time, its nameref attribute is lost.
Re: nameref bug?
On Sat, Aug 30, 2014 at 11:39 AM, lolilolicon wrote: > > As you see, once ref is assigned explicitly, or indeed, is assigned for > a second time, its nameref attribute is lost. OK, here is the minimum script that demonstrates the bug: === script === #!/bin/bash declare var="hello world" declare -n ref ref=var echo $ref ref=var echo $ref --- output --- hello world var The equivalent "1 out of 4" script that works correctly: #!/bin/bash declare var="hello world" func() { local -n ref ref=var echo $ref local -n ref # the workaround ref=var echo $ref } func
Re: nameref bug?
On Sat, Aug 30, 2014 at 11:51 AM, lolilolicon wrote: > On Sat, Aug 30, 2014 at 11:39 AM, lolilolicon wrote: >> >> As you see, once ref is assigned explicitly, or indeed, is assigned for >> a second time, its nameref attribute is lost. > > OK, here is the minimum script that demonstrates the bug: > > === script === > #!/bin/bash > declare var="hello world" > declare -n ref > ref=var > echo $ref > ref=var > echo $ref > > --- output --- > hello world > var > > > The equivalent "1 out of 4" script that works correctly: > > #!/bin/bash > declare var="hello world" > func() { > local -n ref > ref=var > echo $ref > local -n ref # the workaround > ref=var > echo $ref > } > func Ah, LOL I think I need some sleep. This is not a bug. Sorry for all the noise.