我偶然发现了这一点:归结起来,这个例子是
/ # a=$(eval echo hello world)
/ # echo $a
hello world
/ # $(eval echo hello world)
/bin/sh: hello: not found
/ # a=$(hello world)
/bin/sh: hello: not found
我希望第一行扩展到hello world
括号内,然后以与最后一行相同的方式扩展:a=$(hello world)
。毕竟help eval
告诉我们:
将 ARG 组合成单个字符串,使用结果作为 shell 的输入,并执行生成的命令。
如果 eval 确实在展开之前执行了结果命令$()
(我期望如此),则结果应该是一个错误,因为hello world
不可执行(除非有实际hello
命令)
为什么 a=$(eval echo hello world)
没有按预期出错?
答案1
如果 eval 确实在 $() 展开之前执行了结果命令(这是我所期望的),那么结果应该是一个错误,因为 hello world 不可执行(除非存在实际的 hello 命令)
这不是替代的运作方式。仅仅存在$(..)
就会导致eval
甚至运行
首先,$(..)
命令替换在 bash 中是一种捕获在括号内运行的命令的输出并将其存储在变量中的方法。被$(..)
替换为其中存在的内容的输出
该部分
a=$(eval echo hello world)
由 shell 按以下顺序执行。其eval echo hello world
执行方式与运行 echo 命令并输出存储在变量中的echo hello world
字符串一样简单。hello world
a
该部件按照 1) 中的说明
$(eval echo hello world)
返回。hello world
但没有分配捕获$(..)
任何地方的输出。因此,一个文字字符串被返回到 shell iehello world
。 shell 尝试将其解释为命令(文字hello
字符串)。因此您会看到错误,即找不到该名称的命令同样的情况
a=$(hello world)
也发生。如 1) 中所述,该部分$(..)
将括号内的内容作为命令运行。因此再次计算文字字符串会导致相同的错误。
在情况 2) 和 3) 中,当$(..)
展开 时,未加引号的文字字符串hello world
将返回到 shell,该字符串会导致分词hello
并world
作为两个单独的单词。这就是为什么您遇到hello
作为命令运行而不是整个字符串的错误的原因hello world
。
使用任何命令时都要小心eval
,就像 Even 一样简单echo
。如果未正确调用,则存在执行危险命令的风险。看使用总是安全吗eval echo
?