7.2.9. Eval command

In the previous section we used the \\ to escape the $ sign in front of a variable. The last example was:

fruit=apple
echo \$$fruit # gives $apple

This looks like a new variable-value. Can we also access this value ?

% fruit=apple
% apple=jonagold

% echo echo \$$fruit
echo $apple

% echo $(echo \$$fruit)
bash: $apple: command not found

The way it will work is using the shell command eval. This will take a string as argument and evaluate this sting as if it was entered from the command line.

The command line we like to run is in this example echo $apple where the ‘apple’ comes from the expansion of fruit:

% fruit=apple
% apple=jonagold
% eval echo \$$fruit # this expands to "eval echo $apple"
jonagold
% One can also write
echo ${!fruit} # this substitutes the value of the
               # variable 'fruit' as variable name between the braces

eval can be useful to make a variable command. For example, when you like to include a timestamp with every echo command:

% date; echo "There is some error"
Wed 26 Jan 2022 07:49:25 PM CET
There is some error

# The problem is that the date is on a seperate line
# we try the following:

% d=$(date); echo "$d: " "There is some error"
Wed 26 Jan 2022 07:51:00 PM CET:  There is some error

# Now we want to shortcut this to make it more convenient:
ets='d=$(date); echo "$d: "'
$ets "There is an error"
bash: d=$(date);: command not found

# bash sees the first word (d=$(date);) as a command
# we want to execute the line as it is written on the comandline
# just as it worked before: we use eval
eval $ets "There is an error"
Wed 26 Jan 2022 07:54:47 PM CET:  There is an error

# We can also make a shortcut for this:
pts="eval $ets"
$pts "There is an error"
Wed 26 Jan 2022 07:56:44 PM CET:  There is an error

# We can define this in the beginning of our script
# and we use $pts instead of echo everywhere. If we
# want to remove the timestamp we can redefine pts
# without changing the script
pts=echo  # $pts behave now the same as echo

Note: this can maybe better written by using functions.

Maybe the most used case of eval is when starting ssh-agent. This program can keep ssh-keys so that they can be used without asking for a password every time. The standard way of starting this command is:

eval $(ssh-agent)

The reason is, that ssh-agent also need to set some environment variables. It puts this on stdout when starting:

% ssh-agent
SSH_AUTH_SOCK=/tmp/ssh-JQU5mg3DpoIB/agent.28524; export SSH_AUTH_SOCK;
SSH_AGENT_PID=28525; export SSH_AGENT_PID;
echo Agent pid 28525;

Normally, after starting one should manually execute the outputlines. Starting ssh-agent with eval, will start the agent and also ‘eval’ the output lines.