使用有什么区别:
eval 'echo "foo"'
和
echo 'echo "foo"' | bash
有没有?
答案1
简答
运行的命令eval
在当前 shell 中执行,通过管道传送到的命令bash
在子 shell 中执行,例如:
> echo 'x=42' | bash; echo $x
> eval 'x=42'; echo $x
42
更长的答案
在评论中,有人声称在最新版本bash
(>=4.2) 中,第一个命令也可以具有相同的效果。然而,情况似乎并非如此。
实际上有几个因素会导致管道命令不在当前会话中运行:管道和命令bash
。
大多数情况下,管道命令在子 shell 中运行。 Bash 手册 (第 3.2.2 节:管道)有以下说法:
管道中的每个命令都在其自己的子 shell 中执行(请参阅命令执行环境)。
正如评论中指出的,可以通过该lastpipe
选项修改此行为。 Bash 手册 (第 4.3.2 节:内置 Shopt)关于该选项有以下说法lastpipe
:
最后一管
如果设置,并且作业控制未激活,shell 将运行当前 shell 环境中未在后台执行的管道的最后一个命令。
我们可以通过如下方式验证情况是否如此。
首先启用lastpipe
:
> shopt -s lastpipe
然后禁用作业控制:
> set +m
现在执行一个从管道内设置变量的命令:
> unset x
> echo x=42 | while IFS= read -r line; do eval "${line}"; done;
> echo $x
42
请注意,我们使用while
循环和read
命令作为解决方法,因为eval
命令无法从 stdin 读取其输入(因此无法从管道获取其输入)。
此示例演示了管道中最右边的命令实际上可以在当前 shell 中执行。然而这实际上并不影响我们原来的例子。即使lastpipe
启用并禁用作业控制,在管道传输到 时我们仍然会得到以下结果bash
:
> echo 'x=42' | bash; echo $x
>
这是因为bash
命令本身在子 shell 中执行其输入。