Search code examples
bashshellindirection

creating environment variable with user-defined name - indirect variable expansion


I am trying to create an environment variable in bash script, user will input the name of environment variable to be created and will input its value as well.

this is a hard coded way just to elaborate my question :

#!/bin/bash
echo Hello 
export varName="nameX" #
echo $varName 
export "$varName"="val" #here I am trying to create an environment 
#variable  whose name is nameX and assigning it value val
echo $nameX 

it works fine it's output is :

Hello
nameX
val

But, I want a generic code. So I am trying to take input from user the name of variable and its value but I am having trouble in it. I don't know how to echo variable whose name is user-defined

echo "enter the environment variable name"
read varName
echo "enter the value to be assigned to env variable"
read value
export "$varName"=$value

Now, I don't know how to echo environment variable if I do like this :

echo "$varName"

it outputs the name that user has given to environment variable not the value that is assigned to it. how to echo value in it?

Thanks


Solution

  • To get closure: the OP's question boils down to this:

    How can I get the value of a variable whose name is stored in another variable in bash?

    var='value'    # the target variable
    varName='var'  # the variable storing $var's *name*
    

    gniourf_gniourf provided the solution in a comment:

    Use bash's indirection expansion feature:

    echo "${!varName}"  # -> 'value'
    

    The ! preceding varName tells bash not to return the value of $varName, but the value of the variable whose name is the value of $varName.
    The enclosing curly braces ({ and }) are required, unlike with direct variable references (typically).
    See https://www.gnu.org/software/bash/manual/html_node/Shell-Parameter-Expansion.html

    The page above also describes the forms ${!prefix@} and ${!prefix*}, which return a list of variable names that start with prefix.


    bash 4.3+ supports a more flexible mechanism: namerefs, via declare -n or, inside functions, local -n:

    Note: For the specific use case at hand, indirect expansion is the simpler solution.

    var='value'
    
    declare -n varAlias='var'  # $varAlias is now another name for $var
    
    echo "$varAlias" # -> 'value' - same as $var
    

    The advantage of this approach is that the nameref is effectively just an another name for the original variable (storage location), so you can also assign to the nameref to update the original variable:

    varAlias='new value'  # assign a new value to the nameref
    
    echo "$var" # -> 'new value' - the original variable has been updated
    

    See https://www.gnu.org/software/bash/manual/html_node/Shell-Parameters.html


    Compatibility note:

    • Indirect expansion and namerefs are NOT POSIX-compliant; a strictly POSIX-compliant shell will have neither feature.
    • ksh and zsh have comparable features, but with different syntax.