bashvariablesglobal-variableseval

How to modify a global variable within a function in bash?


I'm working with this:

GNU bash, version 4.1.2(1)-release (x86_64-redhat-linux-gnu)

I have a script like below:

#!/bin/bash

e=2

function test1() {
  e=4
  echo "hello"
}

test1 
echo "$e"

Which returns:

hello
4

But if I assign the result of the function to a variable, the global variable e is not modified:

#!/bin/bash

e=2

function test1() {
  e=4
  echo "hello"
}

ret=$(test1)

echo "$ret"
echo "$e"

Returns:

hello
2

I've heard of the use of eval in this case, so I did this in test1:

eval 'e=4'

But the same result.

Could you explain me why it is not modified? How could I save the echo of the test1 function in ret and modify the global variable too?


Solution

  • When you use a command substitution (i.e., the $(...) construct), you are creating a subshell. Subshells inherit variables from their parent shells, but this only works one way: A subshell cannot modify the environment of its parent shell.

    Your variable e is set within a subshell, but not the parent shell. There are two ways to pass values from a subshell to its parent. First, you can output something to stdout, then capture it with a command substitution:

    myfunc() {
        echo "Hello"
    }
    
    var="$(myfunc)"
    
    echo "$var"
    

    The above outputs:

    Hello
    

    For a numerical value in the range of 0 through 255, you can use return to pass the number as the exit status:

    mysecondfunc() {
        echo "Hello"
        return 4
    }
    
    var="$(mysecondfunc)"
    num_var=$?
    
    echo "$var - num is $num_var"
    

    This outputs:

    Hello - num is 4