为什么我不能使用变量作为命令的前缀来设置环境变量?

为什么我不能使用变量作为命令的前缀来设置环境变量?

通常,可以通过像这样添加前缀来为命令设置环境变量:

hello=hi bash -c 'echo $hello'

我还知道我们可以使用变量来替换命令调用的任何部分,如下所示:

$ cmd=bash
$ $cmd -c "echo hi" # equivalent to bash -c "echo hi"

我非常惊讶地发现不能使用变量作为命令前缀来设置环境变量。测试用例:

$ prefix=hello=hi
$ echo $prefix # prints hello=hi
$ $prefix bash -c 'echo $hello'
hello=hi: command not found

为什么无法使用变量设置环境变量?前缀部分是特殊部分吗?我可以通过前面使用 eval 使其工作,但我仍然不明白为什么。我使用的是 bash 4.4。

答案1

我怀疑这是吸引你的序列的一部分:

不是变量赋值或重定向的单词会被扩展(请参阅 Shell 扩展)。如果扩展后仍有单词,则第一个单词将被视为命令名称,其余单词将被视为参数

那是来自Bash 参考手册在简单命令扩展部分。

cmd=bash示例中,没有设置环境变量,bash 通过参数扩展处理命令行,留下bash -c "echo hi".

在该prefix=hello=hi示例中,第一遍中再次没有变量分配,因此处理继续进行参数扩展,从而产生第一个字hello=hi

一旦处理了变量分配,在命令执行期间就不会重新处理它们。

请参阅下面的处理及其结果set -x

$ prefix=hello=hi
+ prefix=hello=hi
$ $prefix bash -c 'echo $hello'
+ hello=hi bash -c 'echo $hello'
-bash: hello=hi: command not found
$ hello=42 bash -c 'echo $hello'
+ hello=42
+ bash -c 'echo $hello'
42

对于“变量扩展”作为“环境变量”的更安全的变体eval,请考虑维詹德里亚的建议env:

prefix=hello=hi
env "$prefix" bash -c 'echo "$hello"'
hi

严格来说,它不是命令行变量分配,因为我们使用env实用程序的主要功能将环境变量分配给命令,但它实现了相同的目标。该$prefix变量在命令行处理期间展开,向 提供名称=值env,然后将其传递给bash

答案2

因为$prefix这不是一项任务。@Jeff 有更长的解释

你可以用函数来做类似的事情:

$ prefix() { hello=hi "$@"; }
$ prefix bash -c 'echo "$hello"'
hi

...如果您愿意,您甚至可以堆叠它们:

$ foo() { foo=123 "$@"; }
$ bar() { bar=456 "$@"; }
$ foo bar bash -c 'echo "$bar $foo"'
456 123

相关内容