1

I have a script foo.sh

 CMD='export FOO="BAR"'
 $CMD
 echo $FOO

It works as expected

 >./foo.sh 
 "BAR"

Now I want to change FOO variable to BAR BAR. So I get script

 CMD='export FOO="BAR BAR"'
 $CMD
 echo $FOO

When I run it I expect to get "BAR BAR", but I get

 ./foo.sh: line 2: export: `BAR"': not a valid identifier
 "BAR 

How I can deal with that?

1
  • My bash version is GNU bash, version 4.1.0(1)-release (i386-apple-darwin13.2.0) Commented Jul 25, 2014 at 12:26

3 Answers 3

3

You should not use a variable as a command by just calling it (like in your $CMD). Instead, use eval to evaluate a command stored in a variable. Only by doing this, a true evaluation step with all the shell logic is performed:

eval "$CMD"

(And use double quotes to pass the command to eval.)

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

4 Comments

Just as a comment: You might be interested in using arrays to store your commands instead of plain string variables. This way you easily can combine the command words and do not have to mind quoting the stuff.
@chepner, this greatly depends on your needs. Since OP did not specify the concrete usecase, I rather tend to accept that what he says is true. A typical "better" way to achieve the goal of using a short thing for a long command is a shell function, of course. But maybe OP is going to store the read the command from a DB, so only a string is possible. In this case using eval is the best solution.
An option is to retrieve the command and the arguments separately. Executing arbitrary code from an external source is the classic example of when not to use eval.
Maybe the source isn't that external and maybe the code therefore isn't that arbitrary. Could be the comands are just read from a private DB which only OP can write. It all depends and while I can imagine valid uses of eval you certainly are right to warn about the security issues with that.
2

Just don't do that.

And read Bash FAQ #50

  1. I'm trying to save a command so I can run it later without having to repeat it each time

If you want to put a command in a container for later use, use a function. Variables hold data, functions hold code.

pingMe() {
    ping -q -c1 "$HOSTNAME"
}

[...]
if pingMe; then ..

5 Comments

Interesting link but it doesn't answer the question.
@LucM sure, because it solves the root of his problem.
Rarely do I see "${CMD[@]}" solutions. Actually I only find myself showing it most of the time. Can't wait to see the time when these posing "Bash FAQ"'s would again absorb it.
Added exact quote from bash faq that helped me.
@StasKurilin It's correct to answer your own question too ;-)
0

The proper way to do that is to use an array instead:

CMD=(export FOO="BAR BAR")
"${CMD[@]}"

2 Comments

If you can replace the plain string of the OP by an array, you should consider to go the whole nine yards and replace it by a shell function ;-)
@Alfe Obviously that's not always practical to situations especially when you're creating a command out of local function arguments.

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.