Answers:
eval "$1"
在当前脚本中执行命令。它可以设置和使用当前脚本中的shell变量,设置当前脚本中的环境变量,设置和使用当前脚本中的函数,设置当前目录,umask,限制和当前脚本中的其他属性,等等。bash -c "$1"
在完全独立的脚本中执行命令,该脚本继承环境变量,文件描述符和其他进程环境(但不将任何更改传回),但不继承内部shell设置(shell变量,函数,选项,陷阱等)。
还有另一种方法,(eval "$1")
它在子shell中执行命令:它继承了调用脚本的所有内容,但不将任何更改传回。
例如,假设dir
未导出变量且变量$1
为cd "$foo"; ls
,则:
cd /starting/directory; foo=/somewhere/else; eval "$1"; pwd
列出/somewhere/else
和打印的内容/somewhere/else
。cd /starting/directory; foo=/somewhere/else; (eval "$1"); pwd
列出/somewhere/else
和打印的内容/starting/directory
。cd /starting/directory; foo=/somewhere/else; bash -c "$1"; pwd
列出/starting/directory
(因为cd ""
不会更改当前目录)的内容并打印/starting/directory
。(eval "$1")
与无关source
。这只是一个组合(…)
和eval
。source foo
大致等于eval "$(cat foo)"
。
eval
和之间的主要区别.dot
是eval
使用参数和.dot
使用文件。
之间最重要的区别
bash -c "$1"
和
eval "$1"
是前者运行在子外壳中,而后者却没有。所以:
set -- 'var=something'
bash -c "$1"
echo "$var"
#there doesn't seem to be anything here
set -- 'var=something'
eval "$1"
echo "$var"
something
我不知道为什么有人会bash
以这种方式使用可执行文件。如果必须调用它,请使用POSIX保证的内置函数sh
。或者,(subshell eval)
如果您想保护环境。
就个人而言,我首先更喜欢外壳.dot
。
printf 'var=something%d ; echo "$var"\n' `seq 1 5` | . /dev/fd/0
something1
something2
something3
something4
something5
实际上,使用其中一个的唯一原因是在您的变量实际分配或评估另一个变量的情况下,或者单词拆分对输出很重要。
例如:
var='echo this is var' ; $var
this is var
那行得通,但这仅仅是因为echo
不关心它的参数计数。
var='echo "this is var"' ; $var
"this is var"
看到?之所以会出现双引号,是因为$var
未评估的壳扩展结果quote-removal
。
var='printf %s\\n "this is var"' ; $var
"this
is
var"
但是用eval
或sh
:
var='echo "this is var"' ; eval "$var" ; sh -c "$var"
this is var
this is var
当我们使用eval
或sh
shell对扩展结果进行第二遍处理并将其评估为潜在命令时,引号也会有所不同。您也可以:
. <<VAR /dev/fd/0
${var:=echo "this is var"}
#END
VAR
this is var
我做了一个快速测试:
time bash -c 'for i in {1..10000}; do bash -c "/bin/echo hi"; done'
time bash -c 'for i in {1..10000}; eval "/bin/echo hi"; done'
(是的,我知道,我使用bash -c来执行循环,但这没有什么区别)。
结果:
eval : 1.17s
bash -c : 7.15s
所以eval
更快。从手册页eval
:
eval实用程序应通过将参数连接在一起并用字符分隔每个参数来构造命令。构造的命令应由外壳读取并执行。
bash -c
当然,在bash shell中执行命令。一个注意事项:我/bin/echo
之所以使用它是因为echo
内置了一个shell bash
,这意味着不需要启动新进程。更换/bin/echo
用echo
的bash -c
试验,花了1.28s
。差不多。但是,eval
运行可执行文件的速度更快。此处的主要区别在于,eval
它不会启动新的外壳程序(它在当前外壳程序中执行命令),而是bash -c
启动一个新的外壳程序,然后在新的外壳程序中执行命令。启动新的shell需要时间,这就是为什么bash -c
它比慢eval
。
bash -c
有eval
没有exec
。
bash -c
是不是那个坏...
e='echo foo'; $e
效果很好。