运行 带有环境变量的存储命令

Running stored command with environment variables

这适用于 sh:

$ export command="true"
$ "$command"

如果我需要将一些变量传递给命令,但是我无法让它工作:

$ export command="env FOO=\"bar\" true"
$ "$command"
sh: 2: env FOO="bar" true: not found

缺少什么?

由于您将 $command 放在引号中,这会阻止 shell 对其内容执行字段拆分,因此它被视为一个单词。因此,它尝试 运行 的 of 命令的名称是 $command 的全部内容,包括它的 spaces 和双引号字符。

您可以省略引号,这几乎可以满足您的要求:

export command="env FOO=\"bar\" true"
$command

除此之外,这会将 FOO 设置为 "bar"(带双引号),而不是您可能期望的 bar(不带引号)。如果您尝试将 FOO 设置为其中包含 space 的内容,它也将不起作用:

$ command="env FOO=\"bar foo\" true"
$ $command
env: foo": No such file or directory

这里的问题是变量 command 中的双引号字符在被替换后被视为与任何其他字符一样。它们不会被删除,也不会阻止字段拆分。

您可以改为使用 eval 命令:

command="env FOO=\"bar foo\" true"
eval "$command"

这会导致 shell 再次完全重新评估 eval 之后的所有内容并作为命令执行。换句话说,在 eval "$command" 上进行替换、拆分、扩展和引号删除之后,它会在 env FOO="bar foo" true 上执行替换、拆分、扩展和引号删除,就好像它是输入到 [=59 中的命令一样=].

但是eval命令是非常危险的。你必须相信你传递给它的一切。如果你传递的东西来自不受信任的用户,那么用户可以制作一个字符串,让他 运行 他想要的任何命令。

作为 eval 的替代方法,您可以使用 alias 或函数。 alias 命令和 eval 一样危险,但是如果您只打算在命令提示符下使用 $command 而从不在脚本中使用,那么使用别名是最简单和最简单的解决方案:

$ alias mycommand="env FOO=\"bar\" true"
$ mycommand

如果您在 shell 脚本中使用它,或者在命令行和 shell 脚本中使用它,我会使用一个函数:

myfunc() {
    env FOO="bar" true
}
myfunc

顺便说一句,当使用 Bourne shell 之一时,您实际上不需要使用 env 为命令设置环境变量,您可以只设置变量:

FOO="bar" true

当这样使用时,变量赋值就像 env 命令一样工作,它不会改变 shell 环境中 FOO 的值,仅在true 命令的环境。