Re: nameref and referenced variable scope, setting other attributes (was "local -g" declaration references local var in enclosing scope)
On Mon, Mar 18, 2024 at 04:19:55PM -0400, Chet Ramey wrote: > On 3/14/24 8:57 PM, Zachary Santer wrote: > > On Thu, Mar 14, 2024 at 3:43 PM Chet Ramey wrote: > > > > > > In fact, before 2020, local -p with no name arguments behaved the same as > > > local without arguments, which just printed all the local variable names > > > at > > > the current scope in the form of assignment statements. That was certainly > > > not usable to reproduce the current state. > > > > While we're kind of on the subject, I find it really odd that the > > ${var@A} parameter expansion will expand to either an assignment > > statement or a 'declare' command, depending on whether or not the > > variable has an attribute set. > > Yes. There is one thing missing: the transformation should expand to a > `declare' command when applied to a local variable at the current scope, > even if there are no attributes to be displayed. Agreed? > > I am less convinced about outputting a `-g' for a global variable when > called from a function scope, but I could be persuaded. This would be logical. Forgot the use case, but it was about a year ago that I needed this. -- Regards, Mike Jonkmans
Re: nameref and referenced variable scope, setting other attributes (was "local -g" declaration references local var in enclosing scope)
On 3/19/24 11:50 AM, Mike Jonkmans wrote: Yes. There is one thing missing: the transformation should expand to a `declare' command when applied to a local variable at the current scope, even if there are no attributes to be displayed. Agreed? I am less convinced about outputting a `-g' for a global variable when called from a function scope, but I could be persuaded. This would be logical. Forgot the use case, but it was about a year ago that I needed this. The former, the latter, or both? -- ``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: nameref and referenced variable scope, setting other attributes (was "local -g" declaration references local var in enclosing scope)
On Tue, Mar 19, 2024 at 02:24:34PM -0400, Chet Ramey wrote: > On 3/19/24 11:50 AM, Mike Jonkmans wrote: > > > > Yes. There is one thing missing: the transformation should expand to a > > > `declare' command when applied to a local variable at the current scope, > > > even if there are no attributes to be displayed. Agreed? > > > > > > I am less convinced about outputting a `-g' for a global variable when > > > called from a function scope, but I could be persuaded. > > > > This would be logical. > > Forgot the use case, but it was about a year ago that I needed this. > > The former, the latter, or both? I can also agree to the former. My use case was with needing the '-g'. -- Regards, Mike Jonkmans
Re: ${var@A}; hypothetical, related parameter transformations
On Mon, Mar 18, 2024 at 6:26 PM Zachary Santer wrote: > > I guess, in bash 5.1+, it could pass > "${assoc[*]@K}" > and then the receiving end could > eval "assoc=( ${assoc_message} )" > if I wanted to avoid declaring the associative array anew. If I wanted to duplicate an indexed array, however, whether in sending it to another process or not, I would need to be able to expand only the right hand side of the compound assignment statement, i.e. ( [5]="Hello" [12]="world!" ) > For my > use case, if, for whatever reason, bash decided to send associative > arrays as compound assignment statements without being in the context > of a declare command, the receiving end would have to have already > declared the associative array variable before eval'ing what it > received. Given that the documentation doesn't specify when bash would > choose to generate an assignment statement vice a declare command, > maybe that would be the safe way to go. Just changed what happens on the receiving end to: eval "${assoc_message#declare * }" to ensure the associative arrays only get declared where I want them to be. I could have done eval "assoc=${assoc_message#*=}" expanding to only the right hand side of the compound assignment statement. This seemed redundant in my case, because the associative arrays are named the same thing in both sending and receiving processes. So I can get a couple of the things I want by manipulating what I get out of ${var@A} with fairly straightforward parameter expansions. If I needed a declare command and wasn't sure if I would get one, I haven't found a way to expand that to something that is guaranteed to be a declare command maintaining attribute settings. I think you're stuck using an if block at that point.
"${assoc[@]@k}" doesn't get expanded to separate words within compound assignment syntax
Configuration Information [Automatically generated, do not change]: Machine: x86_64 OS: msys Compiler: gcc Compilation CFLAGS: -march=nocona -msahf -mtune=generic -O2 -pipe -D_STATIC_BUILD uname output: MINGW64_NT-10.0-19045 Zack2021HPPavilion 3.4.10.x86_64 2024-02-10 08:39 UTC x86_64 Msys Machine Type: x86_64-pc-msys Bash Version: 5.2 Patch Level: 26 Release Status: release Description: The man page's descriptions of ${var@K} and ${var@k}: K Produces a possibly-quoted version of the value of parameter, except that it prints the values of indexed and associative arrays as a sequence of quoted key-value pairs (see Arrays above). k Like the K transformation, but expands the keys and values of indexed and associative arrays to separate words after word splitting. In the section on Arrays, we see: When assigning to an associative array, the words in a compound assignment may be either assignment statements, for which the subscript is required, or a list of words that is interpreted as a sequence of alternating keys and values: name=( key1 value1 key2 value2 ...). These are treated identically to name=( [key1]=value1 [key2]=value2 ...). The first word in the list determines how the remaining words are interpreted; all assignments in a list must be of the same type. When using key/value pairs, the keys may not be missing or empty; a final missing value is treated like the empty string. The "${assoc[@]@k}" transformation doesn't leave the separate key/value words quoted. I'm not sure if the phrasing of the documentation implies that it would or not. As such, I would expect that $ declare -A assoc_2=( "${assoc_1[@]@k}" ) would create assoc_2 as a duplicate of assoc_1. However, we see that the entire expansion becomes the key for a single array element, with its value being the empty string. Repeat-By: $ declare -A assoc_1=( [key 0]='value 0' [key 1]='value 1' [key 2]='value 2' [key 3]='value 3' ) $ unset assoc_2 $ declare -A assoc_2 $ printf '|%s|\n' "${assoc_1[*]@k}" |key 2 value 2 key 3 value 3 key 0 value 0 key 1 value 1| # All one word. Makes sense. $ assoc_2=( "${assoc_1[*]@k}" ) $ declare -p assoc_2 declare -A assoc_2=(["key 2 value 2 key 3 value 3 key 0 value 0 key 1 value 1"]="" ) # Still makes sense. $ printf '|%s|\n' "${assoc_1[@]@k}" |key 2| |value 2| |key 3| |value 3| |key 0| |value 0| |key 1| |value 1| # Got expanded to separate words, like it's supposed to. $ assoc_2=( "${assoc_1[@]@k}" ) $ declare -p assoc_2 declare -A assoc_2=(["key 2 value 2 key 3 value 3 key 0 value 0 key 1 value 1"]="" ) # Here, it did not. If it were up to me, "${scalar@k}" wouldn't do anything different than "${scalar}" and "${assoc[@]@K}" would expand to separate, quoted words. $ scalar='some words' $ printf '|%s|\n' "${scalar@K}" |'some words'| $ printf '|%s|\n' "${scalar@k}" |'some words'| # This is inconsistent with what the @k parameter transformation does with an array. $ printf '|%s|\n' "${assoc_1[*]@K}" |"key 2" "value 2" "key 3" "value 3" "key 0" "value 0" "key 1" "value 1" | $ printf '|%s|\n' "${assoc_1[@]@K}" |"key 2" "value 2" "key 3" "value 3" "key 0" "value 0" "key 1" "value 1" | # Quoted [*] and [@] array expansions do things differently everywhere else I can think of.
Re: Bash printf should diagnose integer overflow
On 3/18/24 12:41, Chet Ramey wrote: I'm not sure what you're using, but that was not my experience on macOS. I am using Fedora 39 (the current version) on x86-64. That could explain our differing experiences. I see several diagnostics (mostly diff output) with "make check" on Fedora 39. The diagnostics can vary from run to run, i.e., they aren't necessarily reproducible. I assumed these were OK because I got 'em before any patches. From my point of view the diff output was sort of random, so I eyeballed it and guessed which outputs mattered and which didn't. Apparently I guessed incorrectly with fw. At some point I suppose it'd be nice if 'make check' succeeded (exit status 0) or failed (nonzero exit status) so that it is easy for non-experts to tell which diagnostics matter; that's what many other packages do. For now I'd rather focus on the integer overflow issues in Bash, while they're fresh in my mind. First, the patched version doesn't build on macOS because your patches don't include . Once you get past that, printf goes into an infinite loop on printf -v s "%b" "" in printstr because `fw' is used unititialized (and randomly set to some ridiculously large value). That and the old test's incorrect expectation that a field width of 9223372036854775825 would always overflow to -1 (a left-adjusted field width of 1) instead of being flagged as overflow are the UB I was talking about. Yes, I see now. I didn't get that behavior on Fedora, perhaps because the junk in fw was benign there. Perhaps at some point we could enable more of GCC's static checking to catch silly mistakes like that. Again, a task for another time. It should be mostly there in the changes I pushed today, once I made it through the above. Thanks, I checked the devel branch against what I submitted, found a few errors, and while reviewing all this found and fixed a few other integer-overflow issues in Bash. Proposed patches attached, in "git format-patch" format so you can use "git am" on them. If there's some reason a patch shouldn't be applied please let me know so that I can stop worrying about that subissue.From ccf906084c3aaf7cd75f0ee1e035986af7d58a82 Mon Sep 17 00:00:00 2001 From: Paul Eggert Date: Mon, 18 Mar 2024 13:44:27 -0700 Subject: [PATCH 01/10] Improve use of HAVE_C_BOOL MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * bashansi.h: If HAVE_C_BOOL, bool works as per C23, so we needn’t include or define any workarounds. In pre-C99 compilers arrange for ‘false’ and ‘true’ as well; although Bash doesn't use either symbol it's safer to be compatible in case some system .h file unwisely uses it. --- bashansi.h | 12 +++- 1 file changed, 7 insertions(+), 5 deletions(-) diff --git a/bashansi.h b/bashansi.h index 4feaadfb..0bac61b4 100644 --- a/bashansi.h +++ b/bashansi.h @@ -35,13 +35,15 @@ # include "ansi_stdlib.h" #endif /* !HAVE_STDLIB_H */ -/* Prefer stdbool.h if we have it, maybe have to rethink this later */ -#if defined (HAVE_STDBOOL_H) -# include -#else -# ifndef HAVE_C_BOOL +/* If bool is not builtin, prefer stdbool.h if we have it. */ +#ifndef HAVE_C_BOOL +# ifdef HAVE_STDBOOL_H +#include +# else #undef bool typedef unsigned char bool; +#define false 0 +#define true 1 # endif #endif -- 2.44.0 From aeb21592ed88cac5072bcd41b2c478766d6e1dee Mon Sep 17 00:00:00 2001 From: Paul Eggert Date: Mon, 18 Mar 2024 13:54:29 -0700 Subject: [PATCH 02/10] Minor mkseq clarification/tuning MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * braces.c (mkseq): All branches of an if end in ‘result[i++] = t;’, so hoist that out of the ‘if’. --- braces.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/braces.c b/braces.c index 444807a7..194000c2 100644 --- a/braces.c +++ b/braces.c @@ -399,7 +399,7 @@ mkseq (intmax_t start, intmax_t end, intmax_t incr, int type, size_t width) QUIT; #endif if (type == ST_INT) - result[i++] = t = itos (n); + t = itos (n); else if (type == ST_ZINT) { size_t tlen; @@ -419,7 +419,6 @@ mkseq (intmax_t start, intmax_t end, intmax_t incr, int type, size_t width) memset (t + (n < 0), '0', width - tlen); } } - result[i++] = t; } else { @@ -428,9 +427,10 @@ mkseq (intmax_t start, intmax_t end, intmax_t incr, int type, size_t width) t[0] = n; t[1] = '\0'; } - result[i++] = t; } + result[i++] = t; + /* We failed to allocate memory for this number, so we bail. */ if (t == 0) { -- 2.44.0 From 3c124056fbd07b31b259ec0fd87781d9a3ed4eed Mon Sep 17 00:00:00 2001 From: Paul Eggert Date: Mon, 18 Mar 2024 13:57:36 -0700 Subject: [PATCH 03/10] Simplify mkseq control MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * braces.c (mkseq): Replace ‘if (!TEST) break; } while (1);’ with ‘} while (TES
Re: "${assoc[@]@k}" doesn't get expanded to separate words within compound assignment syntax
On Tue, Mar 19, 2024 at 11:18 PM Zachary Santer wrote: > > Repeat-By: > > $ declare -A assoc_1=( [key 0]='value 0' [key 1]='value 1' [key > 2]='value 2' [key 3]='value 3' ) > $ unset assoc_2 > $ declare -A assoc_2 > $ printf '|%s|\n' "${assoc_1[*]@k}" > |key 2 value 2 key 3 value 3 key 0 value 0 key 1 value 1| > # All one word. Makes sense. > $ assoc_2=( "${assoc_1[*]@k}" ) > $ declare -p assoc_2 > declare -A assoc_2=(["key 2 value 2 key 3 value 3 key 0 value 0 key 1 > value 1"]="" ) > # Still makes sense. > $ printf '|%s|\n' "${assoc_1[@]@k}" > |key 2| > |value 2| > |key 3| > |value 3| > |key 0| > |value 0| > |key 1| > |value 1| > # Got expanded to separate words, like it's supposed to. > $ assoc_2=( "${assoc_1[@]@k}" ) > $ declare -p assoc_2 > declare -A assoc_2=(["key 2 value 2 key 3 value 3 key 0 value 0 key 1 > value 1"]="" ) > # Here, it did not. This is specific to the compound assignment syntax for an associative array, even. $ unset array_1 $ declare -a array_1 $ array_1=( "${assoc_1[*]@k}" ) $ declare -p array_1 declare -a array_1=([0]="key 2 value 2 key 3 value 3 key 0 value 0 key 1 value 1") $ array_1=( "${assoc_1[@]@k}" ) $ declare -p array_1 declare -a array_1=([0]="key 2" [1]="value 2" [2]="key 3" [3]="value 3" [4]="key 0" [5]="value 0" [6]="key 1" [7]="value 1")
Re: "${assoc[@]@k}" doesn't get expanded to separate words within compound assignment syntax
On Tue, Mar 19, 2024, at 11:18 PM, Zachary Santer wrote: > As such, I would expect that > $ declare -A assoc_2=( "${assoc_1[@]@k}" ) > would create assoc_2 as a duplicate of assoc_1. However, we see that > the entire expansion becomes the key for a single array element, with > its value being the empty string. This isn't specific to ${var[@]@k}. $ kv1='a 1 b 2 c 3' $ kv2=(a 1 b 2 c 3) $ declare -A aa1=($kv1) aa2=(${kv2[@]}) aa3=("${kv2[@]}") $ declare -p aa1 aa2 aa3 declare -A aa1=(["a 1 b 2 c 3"]="" ) declare -A aa2=(["a 1 b 2 c 3"]="" ) declare -A aa3=(["a 1 b 2 c 3"]="" ) A couple of previous discussions: - https://lists.gnu.org/archive/html/bug-bash/2020-12/msg00066.html - https://lists.gnu.org/archive/html/bug-bash/2023-06/msg00128.html -- vq