2

I'm calling some function which sets VARIABLE to some value and return another value. I need to preserver the value of VARIABLE and assigning the function's return value to another VAR. Here is what I tryied:

bar() { VAR="$(foo)" echo $VARIABLE >&2 echo $VAR >&2 } foo() { VARIABLE="test" echo "retval" } bar 

But it prints

retval 

Is there a way to do that?

3 Answers 3

4

ksh has a convenient non-subshelling command substitution construct for this:

#!/bin/ksh foo() { echo "cat" variable="dog" } output="${ foo }" echo "Output is $output and the variable is $variable" 

In bash and other shells, you have to go via a temp file instead:

#!/bin/bash foo() { echo "cat" variable="dog" } # Create a temp file and register it for autodeletion file="$(mktemp)" trap 'rm "$file"' EXIT # Redirect to it and read it back foo > "$file" output="$(< "$file") echo "Output is $output and the variable is $variable" 
Sign up to request clarification or add additional context in comments.

1 Comment

Not in bash in general, no. There are often ways to write around it though. For example, if you only need the variable for a third command whose side effects you don't care about, you can do something like output="$(foo; echo "Variable was set to $variable" >&2)"
3

Well, it may be ugly, but —

In bash, all variables are global unless declared local. Therefore, you can assign VAR directly in foo:

bar() { #### VAR="$(foo)" foo # Just call it echo $VARIABLE >&2 echo $VAR >&2 } foo() { VARIABLE="test" #### echo "retval" VAR="retval" # What would have gone in $VAR before } bar 

Output:

test retval 

Comments

3

BASH does not return a value to the caller the way traditional functional programming languages do. The only thing that BASH functions can return (essentially) are "exit codes" as a result of the function.

To enable a function to provide a result to another function, you should use global variables. By default, all variables are global in scope, unless otherwise specified.

Here is a set of functions with some echo statements around it that might help you understand this:

#!/bin/bash export VARIABLE="" bar() { echo ">>> In function bar() ... " echo " _var :: $_var" echo " VARIABLE :: $VARIABLE" echo ">>> Setting '_var' to value 'local to bar' ... " local _var="local to bar" echo ">>> calling function foo() ... " foo echo ">>> Back in function bar() ... " echo " _var :: $_var" echo " VARIABLE :: $VARIABLE" } foo() { echo ">>> In function foo() ... " local _var="local to foo" VARIABLE="I'm a global variable" echo " _var :: $_var" echo " VARIABLE :: $VARIABLE" } bar 

In the above example, we set the "_var" variable to be local in scope. When "bar()" funs, we set the value of the local "_var" to be "local to bar". We subsequently call the function "foo()"; which sets the local variable "_var" to the value "local to foo".

We also set the global variable "VARIABLE" to the value of "I'm a global variable".

When execution is returned back to the "bar()" function, we print our VARIABLE and _var. VARIABLE results in the string "I'm a global variable".

For details on Return Values from functions in BASH, please see the question Return value in a Bash function.

Here's the results of the above:

>>> In function bar() ... _var :: VARIABLE :: >>> Setting '_var' to value 'local to bar' ... >>> calling function foo() ... >>> In function foo() ... _var :: local to foo VARIABLE :: I'm a global variable >>> Back in function bar() ... _var :: local to bar VARIABLE :: I'm a global variable 

NOTE that we never set the value of VARIABLE in the "bar()" function. It is set in "foo()", and subsequently, we access the results by use of the global variable.

The local variables "_var" also illustrate that the values are only "local" to each function, and by specifying they are local, they have no value or meaning outside of the function itself.

You can use sub-shelling to do what you want. However, subshells operate in a separate process space, so you often will get unintended side effects. To use within a subshell example:

#!/bin/bash export VARIABLE="default global value" function bar() { VAR=$(foo) echo "VARIABLE :: $VARIABLE" echo " VAR :: $VAR" } function foo() { # in theory, VARIABLE is globally scoped, but called in a # subshell, it won't impact/change the calling environment export VARIABLE='test' echo "$VARIABLE" } bar 

Although capturing the output via the subshell in this manner works - if your function returns or outputs more than one value, you may end up with odd behaviors you didn't intend. The above example illustrates that casual observation of the functions indicates that "foo()" would change the value of "VARIABLE" in the global scope. But as it is run in a subshell ('$(foo)') - it doesn't actually change the global VARIABLE value at all.

This can lead to subtle logic bugs in larger scripts, and I'd suggest not using this method. Here's the output of the above snippet:

VARIABLE :: default global vaule VAR :: test 

Comments

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.