Skip to content

Instantly share code, notes, and snippets.

@izabera
Last active June 9, 2025 11:55
Show Gist options
  • Save izabera/e4717562e20eb6cfb6e05f8019883efb to your computer and use it in GitHub Desktop.
Save izabera/e4717562e20eb6cfb6e05f8019883efb to your computer and use it in GitHub Desktop.
magic namerefs

namerefs (introduced in bash 4.0) act as aliases for other variables

var=meow
declare -n ref=var

echo $ref  # prints meow

ref=moo
echo $var  # prints moo

they can also reference a specific element in an array, using declare -n ref='array[1234]'

using this, i have been playing with a neat nameref trick:

tmp=()
declare -n var='tmp[tmp[0]=some_expression_here, 0]'

it uses the auxiliary array tmp to force an arithmetic context, in which it assigns the result of any arbitrary expression to an element of that array, then expands that same element. we can now create magic variables that evaluate any arbitrary expression.

here's a basic counter:

tmp=()
x=0
declare -n counter='tmp[tmp[0]=x++,0]'

for i in {1..10}; do
    echo $counter
done

# prints 0 1 2 3 4 5 6 7 8 9

here's an example that computes the fibonacci numbers:

f=(0 1)
declare -n fib='f[f[2]=f[0], f[0]+=f[1], f[1]=f[2], 0]'

for i in {1..10}; do
    echo $fib
done

# prints 1 1 2 3 5 8 13 21 34 55

this is already very powerful, as it can do many magic things with numbers. but as it turns out, we can do even more: we can use dollar expansions too!

here's a silly clock with magic variables that show the current date and time:

# \D{your-format-here} passes that format to strftime
# but it only works in prompts like $PS1

# ${var@P} expands $var as if it was in your $PS1

date=('\D{%'{Y,m,d,H,M,S}}) # the formats we'll use
months=(- jan feb mar apr may jun jul aug sep oct nov dec)
numbers=({00..60})
tmp=()

declare -n    year='tmp[tmp=${date[0]@P},0]'
declare -n   month='months[10#${date[1]@P}]'
declare -n    day='numbers[10#${date[2]@P}]'
declare -n   hour='numbers[10#${date[3]@P}]'
declare -n minute='numbers[10#${date[4]@P}]'
declare -n second='numbers[10#${date[5]@P}]'

while :; do
    echo $year/$month/$day $hour:$minute:$second
    sleep 1
done

# 2025/jun/06 09:54:13
# 2025/jun/06 09:54:14
# 2025/jun/06 09:54:15
# 2025/jun/06 09:54:16

this is probably one of the coolest things i've ever seen in bash. honestly i am a bit horrified that this works at all, but the resulting code is just so simple and elegant. and it feels like i'm just scratching the surface, there's so much potential.


previous: recursive expansions

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment