简答

简答

使用有什么区别:

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 中执行其输入。

相关内容