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

时间:2011-01-12 12:13:09

标签: shell unix parameter-expansion

调用存储在变量中的某个命令的正确方法是什么?
1和2之间有什么区别吗?

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

4 个答案:

答案 0 :(得分:84)

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

  • 首字拆分
  • 支撑扩张
  • 波浪扩张
  • 参数,变量和算术扩展
  • 命令替换
  • 次要词分裂
  • 路径扩展(aka globbing)
  • 引用删除

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

使用eval "$cmd"除了引用删除阶段之外什么都不做,其中$cmd按原样返回,并作为参数传递给eval,其功能是再次运行整个链执行。

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

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

答案 1 :(得分:5)

如果您这样做eval $cmd 当我们cmd="ls -l"(交互式地并且在脚本中)时,我们得到了期望的结果。在您的情况下,您有一个没有模式的grep管道,因此grep部分将失败并显示错误消息。只有$cmd才会生成“未找到命令”(或某些此类消息)。 因此,请尝试使用eval并使用完成的命令,而不是生成错误消息的命令。

答案 2 :(得分:0)

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

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

在Mac OSX 10.6.8,Bash 3.2.48上进行了测试

答案 3 :(得分:-4)

我认为你应该把

`
变量周围的

(反引号)符号。