bashbuilt-indeclare

What does the bash' builtin `declare -n z` do with the `z` parameter?


I would love to know how bash' declare -n option works when given only a single argument.

For example:

declare -n z
echo "${z}"  # ""          (empty string as expected)
z="somevalue"
echo "${z}"  # ""          (empty string)

declare -n z
echo "${z}"  # ""          (empty string)
z="somevalue"
echo "${z}"  # somevalue   (huwh? How come z is now assigned a value?)

Why does it seem like the second declare call unsets the nameref attribute? How come that the second assignment operation seems to work but the first one doesn't?

I'm using bash version 5.0.17(1)-release


Solution

  • TL;DR: The first assignment fixes which variable z refers to. The second assignment changes the value of that variable. The second call to declare is essentially a no-op; you've already set the nameref attribute on z; doing so a second time changes nothing.


    The first time you use declare, z is uninitialized and undefined. The first assignment to z (whether in the call to declare or subsequent to it) determines which variable z refers to.

    $ declare -n z
    $ echo $z
    
    $ z=somevalue
    $ declare -p z
    declare -n z=somevalue
    

    echo $z at this point produces no value because somevalue itself is undefined.

    Your second call to declare doesn't really do anything to z:

    $ declare -n z
    $ declare -p z
    declare -n z=somevalue
    

    It's still a reference to the variable somevalue. But now your second assignment to z does something different: it assigns a value to the variable somevalue, so that now when you do echo $z, you see the value of the variable somevalue, just as if you had written echo $somevalue.

    It's a little less confusing if we use a different value for the two assignments, so we can distinguish between the referenced variable and its value.

    $ declare -n z
    $ z=foo
    $ declare -p z
    declare -n z=foo
    $ z=9
    $ echo $foo
    9