eval "$1"
executes the command in the current script. It can set and use shell variables from the current script, set environment variables for the current script, set and use functions from the current script, set the current directory, umask, limits and other attributes for the current script, and so on. bash -c "$1"
executes the command in a completely separate script, which inherits environment variables, file descriptors and other process environment (but does not transmit any change back) but does not inherit internal shell settings (shell variables, functions, options, traps, etc.).
There is another way, (eval "$1")
, which executes the command in a subshell: it inherits everything from the calling script but does not transmit any change back.
For example, assuming that the variable dir
isn't exported and $1
is cd "$foo"; ls
, then:
cd /starting/directory; foo=/somewhere/else; eval "$1"; pwd
lists the content of /somewhere/else
and prints /somewhere/else
.
cd /starting/directory; foo=/somewhere/else; (eval "$1"); pwd
lists the content of /somewhere/else
and prints /starting/directory
.
cd /starting/directory; foo=/somewhere/else; bash -c "$1"; pwd
lists the content of /starting/directory
(because cd ""
doesn't change the current directory) and prints /starting/directory
.
Bash functions are exported via the environment. The at
command makes the environment, the umask and the current directory of the calling process available to the script by generating shell code that reproduces the environment. The script executed by your at job is something like this:
#!/bin/bash
umask 022
cd /home/nick
PATH=/usr/local/bin:/usr/bin:/bin; export PATH
HOME=/home/nick; export HOME
…
stupid
Under older versions of bash, functions were exported as a variable with the name of the function and a value starting with ()
and consisting of code to define the function, e.g.
stupid="() {
date
}"; export stupid
This made many scenarios vulnerable to a security hole, the Shellshock bug (found by Stéphane Chazelas), which allowed anyone able to inject the content of an environment variable under any name to execute arbitrary code in a bash script. Versions of bash where with a Shellshock fix use a different way: they store the function definition in a variable whose name contains characters that are not found in environment variables and that shells do not parse as assignments.
BASH_FUNC_stupid%%="() {
date
}"; export stupid
Due to the %
, this is not valid sh syntax, not even in bash, so the at job fails, whether it even attempts to use the function or not. The Debian version of at, which is used in many Linux distributions, was changed in version 3.16 to export only variables that have valid names in shell scripts. Thus newer versions of at don't pass post-Shellshock bash exported functions through, whereas older ones error out.
Even with pre-Shellshock versions of bash, the exported function only works in bash scripts launched from the at job, not in the at job itself. In the at job itself, even if it's executed by bash, stupid
is just another environment variable; bash only imports functions when it starts.
To export functions to an at job regardless of the bash or at version, put them in a file and source that file from your job, or include them directly in your job. To print out all defined functions in a format that can be read back, use declare -f
.
{ declare -f; cat << EOM; } | at now + 1 minute
stupid
EOM
Best Answer
eval
is part of POSIX. Its an interface which can be a shell built-in.Its described in the "POSIX Programmer's Manual": http://www.unix.com/man-page/posix/1posix/eval/
It will take an argument and construct a command of it, which will be executed by the shell. This is the example of the manpage:
$foo
with the value'10'
and$x
with the value'foo'
.$y
, which consists of the string'$foo'
. The dollar sign must be escaped with'$'
.echo $y
.'$foo'
eval
. It will first evaluate$x
to the string'foo'
. Now we have the statementy=$foo
which will get evaluated toy=10
.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