如何执行存储在变量中的命令?


Answers:


95

Unix Shell在执行输入之前,会对输入的每一行进行一系列转换。对于大多数shell,它看起来像这样(摘自bash联机帮助页):

  • 初始分词
  • 大括号扩展
  • 波浪线扩展
  • 参数,变量和算术扩展
  • 命令替换
  • 次要分词
  • 路径扩展(aka遍历)
  • 取消报价

$cmd在参数扩展阶段,直接使用直接将其替换为命令,然后进行以下所有转换。

eval "$cmd"直到引号删除阶段都将使用using ,直到将其$cmd原样返回并作为参数传递给eval,该函数的功能是在执行之前再次运行整个链。

因此,基本上,它们在大多数情况下是相同的,并且在您的命令使用转换步骤直至参数扩展时是不同的。例如,使用括号扩展:

$ cmd="echo foo{bar,baz}"
$ $cmd
foo{bar,baz}
$ eval "$cmd"
foobar foobaz

6
eval "$cmd"不写怎么办eval$($cmd)${$cmd}
史蒂文·卢

2
@StevenLu,这些都不是等效的-故意这样:eval操作将数据解析为语法;因此,它对安全性非常敏感,因此隐式地进行操作将是非常糟糕的形式。
查尔斯·达菲

5

如果您只是在执行操作eval $cmdcmd="ls -l"(以交互方式并在脚本中)执行操作,则将获得所需的结果。在您的情况下,您的管道带有不带模式的grep,因此grep部分将失败,并显示一条错误消息。只是$cmd会生成“找不到命令”(或某些类似消息)消息。因此,请尝试使用eval并使用完成的命令,而不是生成错误消息的命令。


这只是打印错误。应该是“ grep异常”。
Volodymyr Bezuglyy,2011年

然后使用eval而不是$ cmd本身,因为它可能无法正常工作(在我的测试中,在bash和zsh下没有执行)。这就是eval的本意...
Henno Brandsma 2011年

0

$cmd只是将变量替换为其要在命令行上执行的值。 eval "$cmd"在命令行上执行结果值之前执行变量扩展和命令替换

当您想运行不灵活的命令时,第二种方法很有用。
for i in {$a..$b}
格式循环不起作用,因为它不允许使用变量。
在这种情况下,bash或eval的管道是一种解决方法。

在Mac OSX 10.6.8,Bash 3.2.48上测试


-4

我认为你应该把

`

(反引号)符号放在变量周围。


4
这将执行命令的输出,例如,在ls -l的情况下,将生成类似“ total”命令未找到”的消息(例如,因为total ...是ls -l的输出的一部分,因此)不是您想要的东西
Henno Brandsma 2011年
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.