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 "🇨🇭"

@k

And @k is the same, but it removes quotes from keys and values:

declare -a x=("a b" c "d e")
echo "${x[@]@k}"
0 a b 1 c 2 d e

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