0

In eval <command>, how does eval evaluate the following command?

  • does eval create a shell subprocess to evaluate <command>?

  • If not, does eval rely on the current shell process to evaluate it?

Note that

  • eval is a builtin, so there is no subprocess created for eval itself.
  • Right before <command> is executed, there may or may not be a subprocess created to run it, depending on whether <command> isn't a builtin.

The shell subprocess to evaluate the command mentioned above isn't either of the two mentioned in the note.

Thanks.

3

I don't know about underneath, but in practice, it runs it just like source somefile, where it just runs these commands in your current shell process, without spawning a new process.

And also I'd use the word "string" rather than "commands", since that's what it does. This works, but has no command:

$ eval ""

Or this which is not technically a command:

$ eval "x(){ echo test;}"
$ x
test

And to show it's not always making a new process (so I disagree with William):

in one terminal:

$ echo $$
9983
$ eval "sleep 100"  

in another:

$ ps -ef --forest
peter     9983  2840  0 14:21 pts/41   00:00:00  \_ /bin/bash
peter    17339  9983  0 14:26 pts/41   00:00:00  |   \_ sleep 100

But if you do this it does for some reason:

$ eval 'sleep 100' &
[1] 20675

$ ps --forest
  PID TTY          TIME CMD
 9983 pts/41   00:00:00 bash
20675 pts/41   00:00:00  \_ bash
20676 pts/41   00:00:00  |   \_ sleep
20757 pts/41   00:00:00  \_ ps
  • Sorry @peter, I am not following you. What I see is that it does create a new child process in both of your examples. So what you disagree with me? – Willian Paixao Jul 19 '16 at 12:45
  • @WillianPaixao In the eval "sleep 100" example, it created a sleep process, but not a bash process. And you can't see it, but in the x() example, where I ran no command, I believe but cannot prove it didn't make any process, only defined a function, and the function was then available in the original process, which implies it executed the string/script in the original. – Peter Jul 19 '16 at 12:53
  • 1
    Peter, @WillianPaixao : you can observe when new processes are created by running bash under strace (or your OS's equivalent if not running Linux) (strace -f -o bash.strace bash) – Gilles 'SO- stop being evil' Jul 19 '16 at 23:07
  • @Gilles good idea....why didn't I think of strace. And yes I can see it calls clone() for the sleep in background, but not for the other tests: 20172 clone(child_stack=0, flags=CLONE_CHILD_CLEARTID|CLONE_CHILD_SETTID|SIGCHLD, child_tidptr=0x71be36ad89d0) = 20269 – Peter Jul 20 '16 at 6:40
3

What eval effectively does is parse the arguments, expanding variables etc etc and then the resulting string is executed as normal.

So, for example:

$ i=ls
$ eval $i

The eval here will replace $i with ls and then run the ls command as normal (so it will fork()/exec() to run the ls process).

If, however you did

$ i="echo hello"
$ eval $i
hello

then no new process is created because the echo hello is run as a builtin.

We can see no shell is created by setting variables:

$ a=0
$ i="a=100"
$ eval $i
$ echo $a
100

$a could only be set to 100 if that was done in the current shell.

So the eval itself is really just a parser and is done in the current shell; the results of that string may or may not create a new process, same as any other command.

2

Eval does not create a new process just for the purpose of eval.

Eval rather re-runs the parser with a concatenation of the eval-arguments.

The result of this parsing is then run in the same shell. If the arguments however require to create a sub-shell for the command this is done.

So the main purpose of eval is to re-run the parser.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

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