- What is the difference between the ways?
from bash manpage
:
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.
source filename [arguments]
Read and execute commands from filename in the current shell
environment and return the exit status of the last command exe‐
cuted from filename. If filename does not contain a slash, file
names in PATH are used to find the directory containing file‐
name. The file searched for in PATH need not be executable.
When bash is not in posix mode, the current directory is
searched if no file is found in PATH. If the sourcepath option
to the shopt builtin command is turned off, the PATH is not
searched. If any arguments are supplied, they become the posi‐
tional parameters when filename is executed. Otherwise the
positional parameters are unchanged. The return status is the
status of the last command exited within the script (0 if no
commands are executed), and false if filename is not found or
cannot be read.
There are no differences between the two ways.
There is only one note: eval
concatenated all of its arguments, which is then run as a single command. source
reads the contents of a file and executes them. eval
can only build commands from its arguments, not stdin
. So you can not do like this:
printf "ls" | eval
Your example provides the same result, but the purpose of eval
and source
is different. source
is usually used for providing a library for other scripts, while eval
is used only to evaluate commands. You should avoid using eval
if possible, because there is no guarantee that the evaled string is clean; we must do some sanity checks, using subshell
instead.
- If we run some commands in () or {}, which is more preferred?
When you run sequences commands inside curly brace { }
, all commands are run in the current shell, instead of a subshell (which is the case if you run inside parentheses (see bash reference)).
Using subshell ( )
uses more resources, but your current environment is not affected. Using { }
runs all the commands in the current shell, so your environment is affected. Depending on your purpose, you can choose one of them.
If you execute a file directly
/path/to/script/filename
The shebang line will be searched for the interpreter to run it. If you run perl
or sh
with an argument, they'll behave as documented: try to interpret the file as a script in Perl or shell, respectively.
When you explicitly set the interpreter from the command line (such as sh foo.pl
or perl foo.pl
), the shebang line is not used to determine the interpreter to run. It is parsed for possible options, (for example with a #!/usr/bin/perl -w
shebang, running the script as perl foo.pl
will enable the -w
flag) but it is not used to determine which program should interpret the script.
So, running a perl script as sh foo.pl
means your system will try to interpret it as an sh
script instead, despite the perl shebang line.
Best Answer
The
./foobar.sh
file is started by running it with whatever follows the#!
in the first line. If this line reads#!/bin/sh -x
then it would be identical to thesh -x foobar.sh
case (assuming sh is resolved to/bin/sh
from the PATH). Maybe it is not started bysh
butbash
?The
-x
flag prints debug info, i.e. every command before it is executed.