What is the use of the "@a" operator on shell expansions?

Viewed 201

I read in the release notes of Bash 5.1 these the interesting items:

z. The `@a' variable transformation now prints attributes for unset array variables.

aa. The `@A' variable transformation now prints a declare command that sets a variable's attributes if the variable has attributes but is unset.

So let's check how they work. Firstly, with Bash 4.3 to see the progression and see they used to produce the same:

$ declare -A arra=([k1]="v1" [k2]="v2" [k3]="")
$ echo "${arra[@]@a}"
v1 v2
$ echo "${arra[@]@A}"
v1 v2 

Now with Bash 5.1 using a sequence of alternating keys:

$ declare -A arra=(k1 v2 k2 v2 k3)
$ echo "${arra[@]@a}"
A A A
$ echo "${arra[@]@A}"
declare -A arra=([k1]="v1" [k2]="v2" [k3]="" )

So @A is useful to see the definition of the array, whereas @a gives an "A" for every associative value. Does it? Checking on the Bash 5.1 Reference Manual → Arrays section says:

${parameter@operator}

a
The expansion is a string consisting of flag values representing parameter’s attributes.

But I don't see what else apart form an "A" can come as an output. If I use it against a normal variable, it does not produce anything:

$ v=1
$ echo "${v@a}"
                  # nothing
$ v="hello"
$ echo "${v@a}"
                  # nothing
1 Answers

You will see other flags than A when the variables have been declare'd with these flags:

$ declare -i v
$ echo "${v@a}"
i
$

declare knows about these flags: a, A, i, l, n, r, t, u and x (see help declare for the descriptions). Here's a little snippet to see that in action (done in a new session, or unset v before):

$ unset v
$ for f in a A i l n r t u x; do (declare -$f v; echo "$f: ${v@a}"); done
a: a
A: A
i: i
l: l
n: 
r: r
t: t
u: u
x: x
$

Something's happening with -n (a reference). In this case, Bash will return the flag of the target:

$ declare -i a
$ declare -n v=a
$ echo "${v@a}"
i
$

As noticed in the OP comments, the flags can combine in weird and inconsistent ways:

$ # declaring integer AND lowercase
$ declare -il v
$ echo "${v@a}"
il
$ # ???

And just for fun: removing the subshell for declare (so that the flags combine) in the previous snippet:

$ unset v
$ for f in a A i l n r t u x; do declare -$f v; echo "$f: ${v@a}"; done
a: a
bash: declare: v: cannot convert indexed to associative array
A: a
i: ai
l: ail
bash: declare: v: reference variable cannot be an array
n: ail
r: airl
t: airtl
u: airtu
x: airtxu
$

(I did this for fun only, not to show anything special other than some quirky corners of Bash).

Related