1

I got two variables in a bash script. One contains the name of a function within the script while the other one is an array containing KEY=VALUE or KEY='VALUE WITH SPACES' pairs. They are the result of parsing a specific file, and I can't change this.

What I want to do is to invoke the function whose name I got. This is quite simple:

# get the value for the function
myfunc="some_function"
# invoke the function whose name is stored in $myfunc
$myfunc

Consider the function foo be defined as

function foo
{
   echo "MYVAR: $MYVAR"
   echo "MYVAR2: $MYVAR2" 
}

If I get the variables

funcname="foo"
declare -a funcenv=(MYVAR=test "MYVAR2='test2 test3'")

How would I use them to call foo with the pairs of funcenv being added to the environment? A (non-variable) invocation would look like

MYVAR=test MYVAR2='tes2 test3' foo

I tried to script it like

"${funcenv[@]}" "$funcname"

But this leads to an error (MYVAR=test: command not found).

How do I properly call the function with the arguments of the array put in its environment (I do not want to export them, they should just be available for the invoked function)?

2
  • You need to use eval to execute code that you're constructing dynamically. Commented Nov 22, 2017 at 20:44
  • The fact that you will need eval to do this should be considered a major design flaw in your system, and that should be fixed. Commented Nov 22, 2017 at 21:11

2 Answers 2

3

You can do like this:

declare -a funcenv=(MYVAR=test "MYVAR2='test2 test3'")
for pairs in "${funcenv[@]}"; do
    eval "$pairs"
done
"$funcname"

Note however that the variables will be visible outside the function too. If you want to avoid that, then you can wrap all the above in a (...) subshell.

Sign up to request clarification or add additional context in comments.

8 Comments

Using declare might be safer than using eval. If nothing else, it documents that you are defining variables, not executing arbitrary code. (Although that would require you use MYVAR2=test2 test3 without single quotes in the array.)
@chepner I think the evil eval is needed to evaluate the expression, because it may have embedded quoting. (OP said the array content is given, not possible to change)
@janos Yeah, I realized that after I first commented, added the parenthetical to address that. Ideally, and I know the OP said they couldn't change it, the configuration would change, because a configuration system relying on eval is fragile at best.
Compare eval "foo='1 2'" and declare "foo=1 2"; both declare foo to have a value of 1 2. Leave the quotes out of eval, and you get an error trying to run a command named 2 with foo=1 in its environment. Add the quotes to declare, and the quotes are part of the value of foo. There isn't really a way to accommodate both; they simply behave differently.
The benefit of declare over eval can be seen by comparing, for example, eval 'foo=$(echo hi)' and declare 'foo=$(echo hi)'. eval executes the command substitution; declare does not.
|
0

why don't you pass them as arguments to your function?

function f() { echo "first: $1";  echo "second: $2"; }

fn=f; $fn oneword "two words"

1 Comment

because I do already pass arguments to it (left it out for the sake of simplicity), and I do need to differ between arguments and the "second kind of arguments", and need some kind of hashes as well, which both would environment variables provide

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.