Have you ever transformed parameters?
Parameter transformations look like this: ${parameter@operator}.
They seem to be the least known of Bash's parameter expansions.
(Ever used this? Seen elsewhere? Heard about it?)
I've argued that @E is useful and underappreciated. What about the other operators?
Well, let's give them a look. You'll get to know them. Maybe you'll even come to appreciate them.
The operators
They are:
@U, @u, @L
The first three — @U, @u, @L — are alternative ways of changing case.
Upcase all, upcase first, lowercase all:
x=fOOBar; echo "${x@U} ${x@u} ${x@L}" # nope, no @l
FOOBAR FOOBar foobar
Why does Bash have these besides ${x@^^}, ${x@^}, and ${x@,,}?
Is there any reason to pick ${x@U} over ${x@^^} or vice versa?
Why is there no ${x@l}?
No idea.
@E
The useful @E expands backslash escape sequences:
x="Name\tEditor\tAge\nAlice\tEmacs\t42\nBob\tVim\t30\nEmily\tNano\t21" cut -f1,2 <<< "${x@E}"
Name Editor Alice Emacs Bob Vim Emily Nano
@Q
Then there's @Q, which sort of does the opposite: it dollar-quotes the string for reuse:
x="\ Name Editor Alice Emacs" y="${x@Q}" echo "y is $y"
y is $'Name\tEditor\nAlice\tEmacs'
@P
With @P you can use prompt string backslashes:
x="\ Today is \D{%F, %A}. It's now \A. User is \u. This is \s, of course!" echo "${x@P}"
Today is 2042-11-26, Wednesday. It's now 12:42. User is flandrew. This is bash, of course!
So with this we have at least three ways of outputting today's date:
: "\D{%F}"; echo "${_@P}" # Bash builtin printf "%(%F)T\n" # Bash builtin date -I # GNU coreutils
2042-11-26 2042-11-26 2042-11-26
And at least three ways of showing the current path using tilde for home:
: "\w"; echo "${_@P}" # Bash builtin echo "${PWD/$HOME/\~}" # Bash builtin pwd | sed "s,$HOME,\~," # Bash builtin + GNU sed
~/Desktop ~/Desktop ~/Desktop
@A
With @A we can recreate assignment declarations, be it for display or for later evaluation:
# Assign x=foo y=bar # Store assignment declarations in variable z z="${x@A} ${y@A}" # Show declarations of z, x, y echo "${z@A}" echo "${x@A} ${y@A}" # or: echo "$z" # Reassign and show them x=baz y=quux echo "${x@A} ${y@A}" # Restore the previous and show them eval "$z" echo "${x@A} ${y@A}"
z='x='\''foo'\'' y='\''bar'\''' x='foo' y='bar' x='baz' y='quux' x='foo' y='bar'
@a
With @a we can check a variable's attributes:
declare -i x # x is an integer x=42 declare -r x # x is readonly echo "${x@a}"
ir
@K
With @K we can show key–value pairs of indexed arrays...
declare -a x=("a b" c "d e") echo "${x[@]@K}"
0 "a b" 1 "c" 2 "d e"
...and also of associative arrays:
declare -A x=([EU]="🇪🇺" [TK]="🇹🇰" [GL]="🇬🇱" [AQ]="🇦🇶" [NP]="🇳🇵" [CH]="🇨🇭") echo "${x[@]@K}"
EU "🇪🇺" TK "🇹🇰" GL "🇬🇱" AQ "🇦🇶" NP "🇳🇵" CH "🇨🇭"
Inspecting arrays
Behold:
declare -A x=([EU]="European Union" [NZ]="New Zealand" [CH]="Switzerland") cat <<_ ${#x[@]} ${!x[@]} ${x[@]} ${x[@]@Q} ${x[@]@k} ${x[@]@K} ${x[@]@A} _
3 EU NZ CH European Union New Zealand Switzerland 'European Union' 'New Zealand' 'Switzerland' EU European Union NZ New Zealand CH Switzerland EU "European Union" NZ "New Zealand" CH "Switzerland" declare -A x=([EU]="European Union" [NZ]="New Zealand" [CH]="Switzerland" )
As you can see, there're many options to show information about a Bash array.
Why don't Bashers use them more? The main reason might be: they don't know they exist.
📆 2025-11-26