What is the difference between using:

eval 'echo "foo"'

and

echo 'echo "foo"' | bash

is there any?

  • 1
    Here's another variation with slightly different behaviour as to execution environments: ( eval 'echo "foo"' ) – David Foerster May 7 at 15:22
up vote 19 down vote accepted

Short Answer

The command run by eval is executed in the current shell and the command piped to bash is executed in a sub-shell, e.g.:

> echo 'x=42' | bash; echo $x

> eval 'x=42'; echo $x
42

Longer Answer

In the comments the claim was made that in more recent versions of bash (>=4.2) the first command could also have the same effect. However this does not appear to be the case.

There are actually a couple of factors which cause the piped command not to run in the current session: the pipe and the bash command.

For the most part, piped commands run in subshells. The Bash Manual (Section 3.2.2: Pipelines) has the following to say:

Each command in a pipeline is executed in its own subshell (see Command Execution Environment).

As pointed out in the comments, this behavior can be modified via the lastpipe option. The Bash Manual (Section 4.3.2: The Shopt Builtin) has the following to say about the lastpipe option:

lastpipe

If set, and job control is not active, the shell runs the last command of a pipeline not executed in the background in the current shell environment.

We can verify that this is the case as follows.

First enable lastpipe:

> shopt -s lastpipe

Then disable job-control:

> set +m

Now execute a command which sets a variable from within a pipe:

> unset x
> echo x=42 | while IFS= read -r line; do eval "${line}"; done;
> echo $x
42

Notice that we use the while loop and read command as a work-around since the eval command cannot read its input from stdin (hence cannot get its input from a pipe).

This example demonstrates that the right-most command in the pipe can, in fact, be executed in the current shell. However this does not actually affect our original example. Even with lastpipe enabled and job-control disabled, we still get the following result when piping to bash:

> echo 'x=42' | bash; echo $x

>

This is because the bash command itself executes its input in a subshell.

  • that is a good observation, didn't realize that, but yeah I guess that's how pipes work – Alexander Mills May 7 at 4:44
  • Just curious, what is the reason why you did not accept the answer? – Ondřej Xicht Světlík May 7 at 6:36
  • For bash 4.2+ when running a script (or more exactly when jobcontrol is off) and shopt lastpipe is set and the pipeline is not backgrounded, it does run the right-hand end of the pipe in the 'top' shell not a subshell. See unix.stackexchange.com/questions/9954/… and unix.stackexchange.com/questions/136206/readarray-or-pipe-issue – dave_thompson_085 May 7 at 7:35
  • 5
    @dave_thompson_085 The bash command may be executed in the top shell depending on options, but x=42 will assuredly be run in something that can reasonably be called a subshell. – hvd May 7 at 8:40
  • 1
    @AlexanderMills Actually, the pipe isn't the only issue. The bash command will execute its input in a subshell regardless of whether or not a pipe is involved. See the update to my solution for more details. – igal May 9 at 2:25

Your Answer

 

By clicking "Post Your Answer", you acknowledge that you have read our updated terms of service, privacy policy and cookie policy, and that your continued use of the website is subject to these policies.

Not the answer you're looking for? Browse other questions tagged or ask your own question.