OK. You can avoid using eval
by coming up with some other method of twice-evaluating your string. Whatever you do, you need to twice-evaluate because your requirement is to parse a parse.
What I mean is:
this is 'a parsed" command string"'
^ that works out to 3 words:
1: this 2: is 3: a parsed" command string"
The quotes in 3 are not important—they don't matter at all because they're just some characters in a word. The '
syntax quotes used in the original command-line did matter because they were interpreted by the shell's parser to delimit the word. Anything within is just part of the word.
So, if you want to get more words from a single, pre-parsed word, you have to give it back to the shell as input. That's all there is to it—the shell processes input quotes on input. The quotes are used to escape and delimit input in meaningful ways. It would be pretty meaningless—and fairly scary—if the shell just kept at it. Eventually all input would get evaluated away to nothing!
So you need a second evaluation. You can't get that from $(
command substitutions )
because they don't deal with input, they deal with output. Any side-effect of $
word-expansion which you might equate to the generation of more words is really not the case - that is field-splitting. field-splitting on $IFS
and *
globbing are performed by the shell after input words have already been delimited during the parse process.
Now eval
's whole purpose is to eval
uate as input some string which the shell has already received as input. it is exactly the right tool for this, but we can do it otherwise if you insist.
One way is .
source your own output.
string="printf '<%s>\n' 'these are' 'some words' 'i will evaluate again'"
. /dev/fd/0 <<!
$string
!
In that example, the shell evaluates as input its own output. It works:
<these are>
<some words>
<i will evaluate again>
You can do it by calling another shell to evaluate your output as its input:
sh -c "$string"
...the output is the same. You can delay your input by defining a shell alias
:
alias evaled="$string"
evaled
...and again, same output.
The most direct way to do it is:
eval "$string"
The effect is nearly the same as in all of the other examples, but this time I actually did it with the command named for what I meant to do.
eval
gets a bad rap because people who don't understand what it does or why use it anyway. The thing is, you shouldn't use it if you don't understand the effects of doing so. And it can be easy to lose track: the command is evaluated twice—that's once more than normal—and the one time is usually more than enough for most people to wind up at this web site.
So, you should use eval
in this case to do this thing you want to do, because what you want to do is eval
a string. I don't presume to judge why you want to eval
the string, though I expect that there could be better ways of doing it, but when you want the contents of a shell string to be evaluated as shell input, you should use eval
.