x="a=b"
`echo $x`
echo $a
我希望第二行生成“a=b”,并在主 shell 的上下文中执行它,从而产生一个a
带有 value的新变量b
。但是,我真正得到的(如果我手动输入命令)是第二行之后的错误消息,bash: a=b: command not found
为什么呢?
尝试
eval $x
(我们需要 30 个字符才能发布此答案)
您的第一个回显行所做的是在子shell 中运行并将其值返回给被调用者。使用相同的结果可以实现$()
,并且 - 顺便说一下 - 比反引号更易于使用。
所以,你正在做的是首先运行echo $x
(返回a=b
)。并且,由于反引号,a=b
返回到尝试将该行作为命令运行的 shell - 显然 - 将不起作用。
在 shell 中试试这个:
$(echo ls)
你会清楚地看到正在发生的事情。
这是因为 bash 解析命令行的顺序。它在执行变量和命令替换(例如反引号中的命令a=b
)之前查找变量定义(例如)。正因为如此,当时间echo $x
被替换为a=b
时,bash 将其视为变量定义而将其解析为命令为时已晚。$x
如果您只是用作命令(而不是反引号中的 echo),也会发生同样的事情。正如@mvds 的回答一样,该eval
命令可用于强制从头开始重新解析命令,这意味着它将被识别为变量定义:
$ x="a=b"
$ `echo $x`
-bash: a=b: command not found
$ $(echo $x) # Exact same thing, but with cleaner syntax
-bash: a=b: command not found
$ $x # This also does the same thing, but without some extra steps
-bash: a=b: command not found
$ eval "$x" # This will actually work
$ echo $a
b
$ a= # Start over
$ eval "$(echo "$x")" # Another way of doing the same thing, with extra steps
$ echo $a
b
请注意,在使用时,eval
我已将所有引用$x
放在双引号中 - 这是为了防止 bash 解析的后期阶段(例如分词)发生两次,因为 bash 将完成其常规解析过程,然后识别eval
命令,然后再次重做整个解析过程。使用 很容易得到意想不到的结果eval
,这至少消除了一些潜在的麻烦。
你试过$x
那些有趣的撇号吗?没有echo
, echo 似乎仅用于显示字符串,而不是执行命令。