Re: setarray[unsetkey] doesn't trigger nounset in arithmetic context
(I assume this is a continuation of the discussion in #bash on Libera.chat yesterday?) The primary use of `set -u` is to detect misspelled variable names, and misspelled keys for associative arrays seems like a reasonable extension of that, if you assume that they're in some sense a fixed list, like the fixed fields in a C struct. However, Bash's associative arrays more closely resemble Perl hashes, PHP arrays, Python dicts, JS objects, etc, where "missing" entities are normal and expectable. At least some - maybe most - of the time they fulfill roles more similar to these open dynamic structures than to traditional fixed structs, and treating "unset" as a fatal error is not the experience that programmers have using other scripting languages, and is therefore, I would argue, not something that should be added to the Shell, and certainly not as a quiet change to the existing `set -u`. This leads to the conclusion that the fail-if-unset behaviour should be specified on a per-array basis, which means it should be part of `declare` and `local` rather than a global through `set` or `shopt`. If we're heading down this route I have a bunch of other things that overdue to be fixed, including: 1. ${array[@]:start:count} can under some circumstances return elements with indeces >= start+count, completely contravening expectations from other programming languages. There should be a `declare` or `local` option to fix that, and/or a shopt setting. 2. ${#array[@]} gives the number of elements rather than the last index (minus 1). Being able to declare an array as non-sparse (so that all gaps "exist" with some default value) would fix this. -Martin
Re: setarray[unsetkey] doesn't trigger nounset in arithmetic context
On Mon, May 22, 2023 at 07:01:18AM +1000, Martin D Kealey wrote: > [...] and treating "unset" as a fatal error is not the experience that > programmers have using other scripting languages, and is therefore, I would > argue, not something that should be added to the Shell, and certainly not > as a quiet change to the existing `set -u`. Just for the record, Tcl's unset command generates an error if you use it on a nonexistent variable (which includes a nonexistent array element). But it also offers a -nocomplain option, which you may use if you want to unset something that may or may not currently exist. (End tangent.)
Re: setarray[unsetkey] doesn't trigger nounset in arithmetic context
I just realised I expressed an opinion about associative arrays while the original post was about indexed arrays. My take on this is that indexed arrays are almost always "dynamic"; while it's possible to use constant indices to emulate a struct, that is unusual. For most purposes the flexibility in adding & removing from an array is a feature, not a bug. The support for missing elements or 'empty slots' is a bit unusual, but once that's given, it's entirely predictable that "missing" elements are just a normal kind of data, which is where I was heading with my suggestion about non-sparse arrays. On Mon, 22 May 2023 at 07:01, Martin D Kealey wrote: [...] > 2. ${#array[@]} gives the number of elements rather than the last index > (minus 1). Being able to declare an array as non-sparse (so that all gaps > "exist" with some default value) would fix this. > -Martin
Re: setarray[unsetkey] doesn't trigger nounset in arithmetic context
On Mon, May 22, 2023 at 09:27:17AM +1000, Martin D Kealey wrote: > I just realised I expressed an opinion about associative arrays while the > original post was about indexed arrays. > I simply reported that, specifically in arithmetic contexts, when using a variable (not as the lhs of an = assignment), bash only checks that the variable name before "[" is bound to decide whether to trigger nounset or not: $ set -u $ echo "$(( a[0] ))" # correct, a is not set bash: a: unbound variable $ declare b $ echo "$(( b[0] ))" # correct, b is declared, but not set bash: b: unbound variable $ c=() $ echo "$(( c[0] ))" # wrong, it is supposed to error, c[0] is not set 0 $ echo "$(( c[1] ))" # wrong, it is supposed to error, c[1] is not set 0 $ d=11 $ echo "$(( d[0] ))" # correct, d[0] is set 11 $ echo "$(( d[1] ))" # wrong, it is supposed to error, d[1] is not set 0 $ e=([1]= ) $ echo "$(( e[1] ))" # correct, e[1] is set 0 If the variable has a subscript, it is supposed to also check that the array slot is set, and trigger nounset if it is not. If you run the same commands I marked as wrong above with regular non-unset-immune parameter expansions instead of arithmetic expansions, you will see that nounset is triggered if z is set, but the specific index is not. $ set -u $ unset -v z $ echo "${z[0]}" bash: z[0]: unbound variable $ echo "${z[10*RANDOM+1]}" bash: z[10*RANDOM+1]: unbound variable $ z=() # even if z is set, it still trigger nounset $ echo "${z[0]}" bash: z[0]: unbound variable $ echo "${z[10*RANDOM+1]}" bash: z[10*RANDOM+1]: unbound variable $ d=11 $ echo "${d[1]}" bash: d[1]: unbound variable I think this behaviour is unintented and only happens because the code I linked in the original post is forgetting to check that the array slot is set after expanding variables with a subscript, so it doesn't issue the error. This has nothing to do specifically with associative arrays, though they are also affected by the problem. And it also has nothing to do with [*] and [@] having special treatment when used with nounset to follow the behaviour of $* and $@ in POSIX sh. I am not really proposing a major change to the behaviour of nounset, I am only pointing out the incorrect bash behaviour for that case. emanuele6
Re: `wait -n` returns 127 when it shouldn't
On Thu, May 18, 2023 at 3:07 PM Chet Ramey wrote: > > On 5/18/23 7:51 AM, Robert Elz wrote: > > > Apparently, in bash, if the code is running in a (shell) loop (like inside > > a while, or similar, loop) then each iteration around the loop, any jobs > > that > > have exited, but not been cleaned already, are removed from the queue (the > > jobs table in practice, though bash may also have something else). > > > > That's really broken, and should be fixed (but has apparently been that > > way for decades, and no-one noticed). > > This isn't a problem, and is a red herring. The code that manages that list > makes sure to keep as many jobs in the list as POSIX requires, subject to > the maxchild resource limit. > > > > In the script in question, the offending loop isn't the one in the main > > program - in that for each iteration the background processes are started, > > and waited for, in each iteration, but the one in the waitjobs function. > > which (appears at first glance, which is all the analysis shells ever do) > > to be an infinite loop, so each time around, if there are any completed > > jobs in the table, they're removed. > > No, this isn't what happens. The problem is that the shell reaps both jobs, > but the `wait -n' code had a race condition that prevented it from finding > a job in the list. > I fail to see where the race condition in `true & wait -n` is. Whether the 'underlying function' has a race condition is the true red herring here. Also, the manual states: 'If the -n option is supplied, wait waits for a single job from the list of ids or, if no ids are supplied, any job, to complete and returns its exit status.' `true & wait -n` returning 127 means `wait -n` did not wait for 'any job'; in fact, it waited for no job. The subsequent part about 'unwaited-for' children is either irrelevant or contradictory to the above given the current scenario. > -- > ``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/ >