86

调用存储在变量中的某些命令的正确方法是什么?

1和2有区别吗?

#!/bin/sh
cmd="ls -la $APPROOTDIR | grep exception"

#1
$cmd

#2
eval "$cmd"
4

4 回答 4

99

Unix shell 在执行它们之前对每一行输入进行一系列转换。对于大多数 shell,它看起来像这样(取自Bash 手册页):

  • 初始分词
  • 大括号展开
  • 波浪扩展
  • 参数、变量和算术扩展
  • 命令替换
  • 二次分词
  • 路径扩展(又名 globbing)
  • 报价删除

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

usingeval "$cmd"直到引号删除阶段才执行任何操作, where$cmd按原样返回,并作为参数传递给eval,其功能是在执行之前再次运行整个链。

所以基本上,它们在大多数情况下是相同的,并且当您的命令使用到参数扩展的转换步骤时它们会有所不同。例如,使用大括号扩展:

$ cmd="echo foo{bar,baz}"

$ $cmd
foo{bar,baz}

$ eval "$cmd"
foobar foobaz
于 2011-01-12T12:29:59.580 回答
6

如果你只是在我们做的eval $cmd时候做cmd="ls -l"(交互地和在脚本中),你会得到想要的结果。在您的情况下,您有一个带有 grep 没有模式的管道,因此 grep 部分将失败并显示错误消息。只是$cmd会生成“找不到命令”(或类似的)消息。

因此,请尝试使用eval(在"The args are read and concatenated together"附近)并使用已完成的命令,而不是生成错误消息的命令。

于 2011-01-12T12:25:15.337 回答
0

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

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

在 Mac OSX 10.6.8、Bash 3.2.48 上测试

于 2019-06-18T17:10:50.190 回答
-4

我认为你应该把

`

变量周围的(反引号)符号。

于 2011-01-12T12:15:46.113 回答