Configuration Information [Automatically generated, do not change]: Machine: x86_64 OS: cygwin Compiler: gcc Compilation CFLAGS: -g -O2 uname output: MSYS_NT-10.0-22631 ZackFramework16 3.6.4-dea57136.x86_64 2025-09-22 06:28 UTC x86_64 Msys Machine Type: x86_64-pc-cygwin
Bash Version: 5.3 Patch Level: 0 Release Status: maint Devel branch commit 6edfd0bf64 On Fri, Oct 17, 2025 at 3:35 PM Mark March <[email protected]> wrote: > > The ${var@A} expansion is defined as follows: > > > The expansion is a string in the form of an assignment statement or declare > > command that, if evaluated, recreates parameter with its attributes and > > value. > > Moreover, if the nameref references an array, the initializer in the declare > statement is incorrect even for the array variable referenced by the nameref: > it contains the first element of the array, not the entire array. This is how this works without going through a nameref, too. $ declare -a array=( zero one two three ) $ printf '%s\n' "${array@A}" declare -a array='zero' $ printf '%s\n' "${array[*]@A}" declare -a array=([0]="zero" [1]="one" [2]="two" [3]="three") $ printf '%s\n' "${array[@]@A}" declare -a array=([0]="zero" [1]="one" [2]="two" [3]="three") $ declare -p array declare -a array=([0]="zero" [1]="one" [2]="two" [3]="three") >From the Arrays section of the manual: > Referencing an array variable without a subscript is equivalent to > referencing the array with a subscript of 0. So you can kind of see where that came from, even if the output would only allow you to correctly reproduce part of the array. $ printf '%s\n' "${array[1]@A}" declare -a array='one' $ printf '%s\n' "${array[2]@A}" declare -a array='two' These wouldn't reproduce anything correctly. And contrast this: $ declare -p 'array[0]' bash: declare: array[0]: not found $ declare -p 'array[1]' bash: declare: array[1]: not found $ declare -p 'array[2]' bash: declare: array[2]: not found Point is, if you're trying to use ${var@A} to reproduce an indexed or associative array, you almost certainly want ${array[*]@A}. > $ echo $BASH_VERSION > 5.3.0(1)-release > > $ declare -a array=(1 2 3) > $ declare -n nameref=array > > $ echo ${nameref@A} > declare -a array='1' > > $ declare -p nameref > declare -n nameref="array" There's a lot to say about how a nameref interacts with an array in general. $ declare -n nameref=array $ printf '%s\n' "${nameref@A}" declare -a array='zero' $ printf '%s\n' "${nameref[*]@A}" declare -a array=([0]="zero" [1]="one" [2]="two" [3]="three") $ printf '%s\n' "${!nameref@A}" declare -a array='zero' $ printf '%s\n' "${!nameref[*]@A}" bash: zero one two three: invalid variable name $ printf '%s\n' "${!nameref[@]@A}" bash: zero one two three: invalid variable name $ printf '%s\n' "${!nameref}" array $ printf '%s\n' "${!nameref[1]@A}" # Expands to nothing. $ printf '%s\n' "${nameref[1]@A}" declare -a array='one' $ nameref=ten $ declare -p array declare -a array=([0]="ten" [1]="one" [2]="two" [3]="three") # Assigned to index 0 $ nameref=( four five six seven ) $ declare -p array declare -a array=([0]="four" [1]="five" [2]="six" [3]="seven") # Compound assignment works. $ nameref[2]=twelve $ declare -p array declare -a array=([0]="four" [1]="five" [2]="twelve" [3]="seven") # Assignment to a specific index works. $ declare -n nameref=array[1] $ printf '%s\n' "${!nameref}" array[1] $ nameref=eleven $ declare -p array declare -a array=([0]="four" [1]="eleven" [2]="twelve" [3]="seven") # This works. $ printf '%s\n' "${nameref[*]@A}" # Expands to nothing. $ printf '%s\n' "${nameref@A}" # Expands to nothing. $ nameref=( 100 101 102 ) bash: `array[1]': not a valid identifier # This error message doesn't make a lot of sense. $ array[1]=( 100 101 102 ) bash: array[1]: cannot assign list to array member # This error message would've been better for that. The nameref can refer to the entire array *or* a single element of the array, and most operations work how you would expect them to, either way. > Similarly for ${var@a}: > > $ echo ${nameref@a} > a $ declare -n nameref=array $ printf '%s\n' "${!nameref@a}" a $ printf '%s\n' "${!nameref[1]@a}" $ printf '%s\n' "${nameref[1]@a}" a $ printf '%s\n' "${nameref[*]@a}" a a a a > I was wondering if you could change the behavior of @a and @A expansions on > namerefs to match the output > of declare -p ? On Fri, Oct 17, 2025 at 3:48 PM Chet Ramey <[email protected]> wrote: > > Interesting question. In every other word expansion, referencing a nameref > variable performs the resolution and uses the variable the nameref resolves > to. The only places you can get to the nameref directly are `declare' and > `unset'. Is this enough of a special case to make it different? $ printf '%s\n' "${!nameref@Q}" 'four' $ printf '%s\n' "${!nameref[1]@Q}" # Nothing. $ printf '%s\n' "${!nameref[0]@Q}" # Nothing ${!parameter[index]@operator} could be made to dereference the nameref like it appears to do with parameter transformations lacking an index. If the @A and @a parameter transformations are made to mirror declare -p, today's functionality would still be available. Might be hard to arrive at these expansions without some documentation specific to them, though.
