326

What can you do with the eval command? Why is it useful? Is it some kind of a built-in function in bash? There is no man page for it..

7
  • 46
    Use type command to learn of what type a command is. (type eval in ths case) Oct 22, 2011 at 20:38
  • 33
    "eval is a shell builtin" Jul 11, 2016 at 16:26
  • 8
    help eval to get "man" page from your shell
    – m-ric
    Nov 28, 2016 at 19:36
  • 1
    eval is a bash-builtin and is documented in the man page of bash. So just type "man bash" and search for the appropriate section for eval. This applies for other bash-builtins, too. Dec 20, 2017 at 19:58
  • @m-ric help eval zsh: command not found: help doesn't work? Jun 7, 2022 at 21:46

11 Answers 11

244

eval is part of POSIX. It's an interface which can be a shell built-in.

It's described in the "POSIX Programmer's Manual": http://www.unix.com/man-page/posix/1posix/eval/

eval - construct command by concatenating arguments

It will take an argument and construct a command of it, which will then be executed by the shell. This is the example from the manpage:

foo=10 x=foo    # 1
y='$'$x         # 2
echo $y         # 3
$foo
eval y='$'$x    # 5
echo $y         # 6
10
  1. In the first line you define $foo with the value '10' and $x with the value 'foo'.
  2. Now define $y, which consists of the string '$foo'. The dollar sign must be escaped with '$'.
  3. To check the result, echo $y.
  4. The result of 1)-3) will be the string '$foo'
  5. Now we repeat the assignment with eval. It will first evaluate $x to the string 'foo'. Now we have the statement y=$foo which will get evaluated to y=10.
  6. The result of echo $y is now the value '10'.

This is a common function in many languages, e.g. Perl and JavaScript. Have a look at perldoc eval for more examples: http://perldoc.perl.org/functions/eval.html

6
  • 8
    In shell terminology, eval is a built-in, not a function. In practice, built-ins behave a lot like functions that don't have an in-language definition, but not quite (as becomes apparent if you are twisted enough to define a function called eval). Oct 23, 2011 at 1:17
  • 9
    What is the difference between eval and backticks ` ?
    – JohnyTex
    Mar 20, 2015 at 9:16
  • 14
    Backticks are shorthand for executing another entire shell, meaning you'll have another child bash/sh process running within your script.
    – Aaron R.
    Oct 19, 2015 at 15:38
  • 1
    Why echo $y (stage 3) brings back foo(10) instead of $foo ? (i.e just the value of foo instead of the string $ + the value of foo) ?
    – user149572
    Dec 25, 2016 at 17:00
  • 1
    @Benia Because $y is defined right above it as a literal $ followed by the value of $x which exands to foo.
    – Ken Sharp
    Jan 30, 2017 at 13:06
94

Yes, eval is a bash internal command so it is described in bash man page.

eval [arg ...]
    The  args  are read and concatenated together into a single com-
    mand.  This command is then read and executed by the shell,  and
    its  exit status is returned as the value of eval.  If there are
    no args, or only null arguments, eval returns 0.

Usually it is used in combination with a Command Substitution. Without an explicit eval, the shell tries to execute the result of a command substitution, not to evaluate it.

Say that you want to code an equivalent of VAR=value; echo $VAR. Note the difference in how the shell handles the writings of echo VAR=value:

1.

    andcoz@...:~> $( echo VAR=value )
    bash: VAR=value: command not found
    andcoz@...:~> echo $VAR
    <empty line>

The subshell executes the echo command and then command substitutes the result, VAR=value, back to the outer shell where it throws the error because "VAR=value" is not a command. The assignment remains ineffective because it was never executed, only echoed.

2.

    andcoz@...:~> eval $( echo VAR=value )
    andcoz@...:~> echo $VAR
    value

The subshell echoes "VAR=value" which is again command substituted back to the outer shell where it is then evaled.

Last but not least, eval can be a very dangerous command. Any input to an eval command must be carefully checked to avoid security problems.

5
  • very nice answer
    – netskink
    Jan 7, 2022 at 14:15
  • Perhaps when you say Without an explicit eval, the shell tries to execute the result of a command substitution, not to evaluate it. In your answer you should explain what the difference is between those two with a definition before going to a lengthy example? Ok, will try to go through it to write such an answer. Jun 7, 2022 at 21:48
  • this seems like a good answer. Will go through it. Another common example I've seen is eval $(opam env) e.g. here: stackoverflow.com/questions/72522412/… Jun 8, 2022 at 14:24
  • when you talk about a "subshell" what are you referring to? Jun 8, 2022 at 14:57
  • 1
    what confuses me is that $(echo Var=value) that $(...) does is "allows a command to be run and its output to be pasted back on the command line as arguments to another command." So to me the output of $(...) should have been given to the terminal as I typed it to the terminal i.e. Var=val which does let me run it. Instead I don't know to what function it's been given that interprets the output of $(...) as commands to be ran. Very confusing to me. tldr: what is the function receiving the output of $(...) and what is the string output of $(...)? Jun 8, 2022 at 15:05
36

The eval statement tells the shell to take eval’s arguments as command and run them through the command-line. It is useful in a situation like below:

In your script if you are defining a command into a variable and later on you want to use that command then you should use eval:

/home/user1 > a="ls | more"
/home/user1 > $a
bash: command not found: ls | more
/home/user1 > # Above command didn't work as ls tried to list file with name pipe (|) and more. But these files are not there
/home/user1 > eval $a
file.txt
mailids
remote_cmd.sh
sample.txt
tmp
/home/user1 >
2
  • 14
    The comment in line 4 of your example is wrong: It should be "Above command didn't work because bash tried to find a command called ls | more. In other words: The single command name consisted of nine characters, including the spaces and the pipe symbol.
    – cfi
    Oct 16, 2015 at 13:41
  • 1
    I get exactly the same behavior he reported. bash --version == GNU bash, version 3.2.57(1)-release (x86_64-apple-darwin18) Apr 26, 2019 at 17:24
34

What is eval?

eval is a shell command which is usually implemented as a builtin.

In POSIX it is listed as part of "2.14. Special Built-In Utilities" at the entry "eval".
What builtin means is:

The term "built-in" implies that the shell can execute the utility directly and does not need to search for it.

What does it do?

In simple terms: makes an input line to be parsed twice.

How does it do that?

The shell has a sequence of steps that it follows to "process" a line. You could look at this image and realize that eval is the only line that goes up, back to step 1, on the left. From the POSIX description:

2.1 Shell Introduction

  1. The shell reads its input ....
  2. The shell breaks the input into tokens: words and operators
  3. The shell parses the input into simple and compound commands.
  4. The shell performs various expansions (separately) ...
  5. The shell performs redirection and removes redirection operators and their operands from the parameter list.
  6. The shell executes a function, built-in, executable file, or script ...
  7. The shell optionally waits for the command to complete and collects the exit status.

At step 6 a built-in will be executed.
At step 6 eval causes the processed line to be sent back to step 1.
It is the only condition under which the execution sequence goes back.

That is why I say: With eval an input line is parsed twice.

Effects of parsing twice.

The first.

And most important effect to understand. Is that one consequence of the first time a line is subject to the seven shell steps shown above, is quoting. Inside step 4 (expansions), there is also a sequence of steps to perform all expansions, the last of which is Quote Removal:

Quote removal shall always be performed last.

So, always, there is one level of quoting removed.

Second.

As consequence of that first effect, additional/different parts of the line become exposed to the shell parsing and all the other steps.

Example.

Indirection.

That allows to execute indirect expansions:

a=b b=c    ;    eval echo \$$a            ### shall produce "c"

Why? Because on the first loop, the first $ is quoted.
As such, it is ignored for expansions by the shell.
The next $ with the name a is expanded to produce "b".
Then, one level of quoting is removed, making the first $ unquoted.
End of first loop.

It is then, on the second loop that the string $b is read by the shell.
Then expanded to "c"
And given as an argument to echo.

To "see" what eval will produce on the first loop (to be evaluated again), use echo. Or any command/script/program that clearly shows the arguments:

$ a=b b=c
$ eval echo \$$a;
c

Replace eval by echo to "see" what is happening:

$ echo echo \$$a
echo $b

It is also possible to show all the "parts" of a line with:

$ printf '<%s> ' echo \$$a
<echo> <$b>

Which, in this example, is only one echo and one variable, but remember it to help in evaluating more complex cases.

A correction.

It must be said that: there is a mistake in the code above, can you see it?.
Easy: there are some quotes missing.

How? you may ask. Simple, let's change the variables (not the code):

$ a=b b="hi     jk"
$ eval echo \$$a
hi jk

See the missing spaces?
That is because the value inside $b was split by the shell.

If that does not convince you, try this:

$ a=b b="hi  *  jk"
$ eval echo \$$a              ### warning this will expand to the list  
                              ### of all files in the present directory.

Why?

Missing quotes. To make it work correctly (add internal "$a"and external \" quotes).
Try this (is perfectly safe):

$ a=b b="hi      *       jk"
$ eval echo \" \$"$a" \"
hi      *       jk

About the manual:

There is no man page for it..

No, there is not an independent man page for this. The search for manual with man -f eval or even apropos eval show no entry.

It is included inside man bash. As is any built-in.
Search for "SHELL BUILTIN COMMANDS" and then for "eval".

An easier way to get help is: In bash, you could do help eval to see the help for the built-in.

Why is eval called evil?

Because it is binding text to code dynamically.

In other words: it converts the list of its arguments (and/or expansions of such arguments) into an executed line. If for any reason, an argument has been set by an attacker, you will be executing attacker code.

Or even simpler, with eval you are telling whoever defined the value of one or several arguments:

C'mon, sit here and type any command line, I will execute it with my powers.

Is that dangerous? Should be clear for everyone that it is.

The safety rule for eval should be:
Only execute eval on variables to which you have given it's value.

Read more detail here.

4
  • 1
    the only really usefull explanation
    – Alex
    Jan 28, 2021 at 17:23
  • Thank you for the detailed explanation. I have a question on the term you used: "quoted". On the first example I see the $ being escaped, not quoted. Is escaped characters the same as quoted with single quotes (except for the few escapes allowed inside single quoted text)? Does the documentation refer to escaped text as quoted text? If that's the case I'll want to re-read it to make things clearer in my head.
    – Spidey
    May 21, 2021 at 21:36
  • This link is broken: You could [look at this image](http://helios.cs.ifmo.ru/~ad/Documentation/Bash_Shell/bash3-CHP-7-SECT-3.html) and realize...
    – Seamus
    Feb 4, 2022 at 17:56
  • V. good & thorough answer, but: I found this answer trying to understand this one-liner: eval "$(ssh-agent -s)". As I understand it, ssh-agent must be running in the background to support ssh-add & other key ops. Unfortunately, I still don't understand this :/
    – Seamus
    Feb 4, 2022 at 18:05
24

eval has no man page because it is not a separate external command, but rather a shell built-in, meaning a command internal to and known only by the shell (bash). The relevant part of the bash man page says:

eval [arg ...]
    The args are read and concatenated together into a single command.  
    This command is then  read  and executed by the shell, and its exit 
    status is returned as the value of eval.  If there are no args, or only 
    null arguments, eval returns 0

In addition, the output if help eval is:

eval: eval [arg ...]
    Execute arguments as a shell command.

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

    Exit Status:
    Returns exit status of command or success if command is null.

eval is a powerful command and if you intend to use it you should be very careful to head off the possible security risks that come with it.

0
17

eval is a feature of most interpreted languages (TCL, python, ruby...), not only shells. It's used to evaluate code dynamically.

In shells, it's implemented as a shell builtin command.

Basically, eval takes a string as argument and evaluates/interprets the code in it. In shells, eval can take more than one argument, but eval just concatenates those to form the string to evaluate.

It's very powerful because you can construct code dynamically and run it, something you can't do in compiled languages like C.

Like:

varname=$1 varvalue=$2
eval "$varname=\$varvalue" # evaluate a string like "foo=$varvalue"
                           # which in Bourne-like shell language
                           # is a variable assignment.

But it's also dangerous as it's important to sanitize the dynamic (externally provided) parts of what is passed to eval for the very reason it's interpreted as shell code.

For instance, above if $1 is evil-command; var, eval would end-up evaluating the evil-command; var=$varvalue shell code and then run that evil-command.

The evilness of eval is often over-exaggerated.

OK, it's dangerous, but at least we know it's dangerous.

A lot of other commands will evaluate shell code in its arguments if not sanitized, like (depending on the shell), [ aka test, export, printf, GNU sed, awk, and of course sh/bash/perl and all interpreters...

Examples (here using uname as the evil-command and $a as externally provided unsanitized data):

$ a='$(uname>&2)' sh -c 'eval "echo $a"'
Linux

$ a='x[0$(uname>&2)]' mksh -c 'export "$a=$b"'
Linux
$ a='x[0$(uname>&2)]' ksh93 -c 'printf "%d\n" "$a"'
Linux
0
$ a='x[0$(uname>&2)]' ksh93 -c '[ "$a" -gt 0 ]'
Linux
$ a=$'bar/g;e uname>&2\n;s//'; echo foo | sed "s/foo/$a/g"
Linux
bar
$ a='";system("uname");"'; awk "BEGIN{print \"$a\"}"

Linux
$ a=';uname'; sh -c "echo $a"

Linux

Those sed, export... commands could be considered more dangerous because while it's obvious eval "$var" will cause the content of $var to be evaluated as shell code, it's not so obvious with sed "s/foo/$var/" or export "$var=value" or [ "$var" -gt 0 ]. The dangerosity is the same, but it's concealed in those other commands.

2
  • @BinaryZebra, sed like eval is being passed a string contained in a variable, and for both, the content of that string ends up being evaluated as shell code, so sed is as dangerous as eval, that's what I'm saying. sed is being passed a string containing uname (uname has not been executed so far) and through the invocation of sed, the uname command ends up being executed. Like for eval. In sed 's/foo/$a/g', you're not passing unsanitized data to sed, that's not what we're talking about here. Dec 19, 2015 at 20:52
  • Great answer, really clarifies it for me. We can use eval to dynamically assign both values and variable names! Aug 10, 2020 at 18:57
16

This example may shed some light:

#!/bin/bash
VAR1=25
VAR2='$VAR1'
VAR3='$VAR2'
echo "$VAR3"
eval echo "$VAR3"
eval eval echo "$VAR3"

Output of the script above:

$VAR2
$VAR1
25
2
  • Thanks for your contribution, but, as entertaining as they are, we aren’t really interested in compiling a list of (slightly different) examples of using eval. Do you believe that there is some fundamental, critical aspect of the functionality of eval that isn’t covered in the existing answers? If so, then explain it, and use the example to illustrate your explanation.  Please do not respond in comments; edit your answer to make it clearer and more complete. Sep 14, 2018 at 16:43
  • This example may be confusing because not everyone understands the difference between single and double quotes in bash. Put all those variables in double quotes and it will bring a different result.
    – t7e
    Jun 21, 2022 at 22:29
2

A bit late to the party on this but this little example from my console output shows the behaviour of eval versus running a script. It shows that eval evaluates a string (be it from a file or variable) and runs the command in the current shell it's in, compared to running a script, which runs in its own shell and exits back to the current shell. (but also to run a script in the current shell environment, you can just place a dot and a space before the shell script filename)

$ pwd
/home/user1

$ cat myscript.sh
cd Desktop

$ ./myscript.sh

$ pwd
/home/user1

$ eval $(cat myscript.sh)

$ pwd
/home/user1/Desktop
1
  • 1
    You probably need to quote the expansion of the command substitution. Test it with a directory that has space in its name (the script would do cd "My dir").
    – Kusalananda
    Jun 14, 2021 at 12:20
2

My experience with eval it can convert string output of command to variable , this example from another question

eval $(ffprobe -v error -of flat=s=_ -select_streams v:0 -show_entries stream=height,width ${FILE})

when I type it directly to the terminal, I got

streams_stream_0_width=1280
streams_stream_0_height=720

That stored each one into a new variable to use it inside the script.

IN_WIDTH=${streams_stream_0_width}

This could be useful to benefit, from another command output, before processing the main command (e.g get file properties or remote server status )

1

The eval function/macro evaluates Shell code represented as a string and returns its completion value.

The source is parsed as a bash shell.

0

Simply put, eval takes all the arguments provided to it, combines them into a single command, and then executes that command.

command_part1="ls"
command_part2="-l"
eval "$command_part1 $command_part2"

is the same as

ls -l

You must log in to answer this question.

Not the answer you're looking for? Browse other questions tagged .