why does a=$(eval echo hello world) not error out?

All we need is an easy explanation of the problem, so here it is.

I stumbled over this: Boiled down the example is

/ # a=$(eval echo hello world)
/ # echo $a
hello world
/ # $(eval echo hello world)
/bin/sh: hello: not found
/ # a=$(hello world)
/bin/sh: hello: not found

I would expect that the first line expands to hello world inside the parentheses and is then expanded the same way the last line is: a=$(hello world). After all help eval tells us:

Combine ARGs into a single string, use the result as input to the shell, and execute the resulting commands.

If eval does execute the resulting command before expansion of $() takes place—which I expect—the result should be an error for hello world is not executable (unless there is an actual hello command)

Why does a=$(eval echo hello world) not error out as expected?

How to solve :

I know you bored from this bug, So we are here to help you! Take a deep breath and look at the explanation of your problem. We have many solutions to this problem, But we recommend you to use the first method because it is tested & true method that will 100% work for you.

Method 1

If eval does execute the resulting command before expansion of $() takes place—which I expect—the result should be an error for hello world is not executable (unless there is an actual hello command)

That is not how substitution works. The mere presence of $(..) is what causes the eval to even run


To start with, $(..) Command substitution in bash is a way to capture the output of command run inside parens and storing it in a variable. The $(..) is replaced by output of contents present inside it

  1. The part a=$(eval echo hello world) is executed by the shell in following order. The eval echo hello world is executed simply as echo hello world which runs the echo command and outputs the string hello world which is stored into the variable a.

  2. The part $(eval echo hello world) just returns hello world as explained in 1). But there is no assignment to capture the output of $(..) anywhere. So a literal string is returned back to the shell i.e. hello world. The shell tries to interpret that as a command (the literal hello string). Hence the error you see, that a command not found of the name

  3. The same happens for a=$(hello world) also. As mentioned in 1), the part $(..) runs the contents inside the parens as commands. So the literal string is evaluated again resulting in the same error.

In cases 2) and 3), when the $(..) is expanded, the literal unquoted string hello world was returned back to the shell which was subject to word splitting causing hello and world as two separate words. Thats why you encounter the error that hello was run as a command and not the whole string hello world.


Be cautious in using eval with any command, as simple as even echo. There is a risk of executing dangerous commands when not properly invoked. See Is it always safe to use eval echo?

Note: Use and implement method 1 because this method fully tested our system.
Thank you 🙂

All methods was sourced from stackoverflow.com or stackexchange.com, is licensed under cc by-sa 2.5, cc by-sa 3.0 and cc by-sa 4.0

Leave a Reply