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

wbk*_*ang 11 bash environment-variables variable

通常,可以通过为命令添加前缀来为命令设置环境变量,如下所示:

hello=hi bash -c 'echo $hello'
Run Code Online (Sandbox Code Playgroud)

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

$ cmd=bash
$ $cmd -c "echo hi" # equivalent to bash -c "echo hi"
Run Code Online (Sandbox Code Playgroud)

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

$ prefix=hello=hi
$ echo $prefix # prints hello=hi
$ $prefix bash -c 'echo $hello'
hello=hi: command not found
Run Code Online (Sandbox Code Playgroud)

为什么我不能使用变量设置环境变量?前缀部分是特殊部分吗?我能够通过在前面使用 eval 让它工作,但我仍然不明白为什么。我正在使用 bash 4.4。

Jef*_*ler 14

我怀疑这是抓住你的序列的一部分:

不是变量赋值或重定向的词被扩展(参见 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
Run Code Online (Sandbox Code Playgroud)

要获得比 更安全的“变量扩展”-as-“环境变量”变体eval,请考虑wjandrea 的建议env

prefix=hello=hi
env "$prefix" bash -c 'echo "$hello"'
hi
Run Code Online (Sandbox Code Playgroud)

这不是严格的命令行变量分配,因为我们使用了env实用程序的主要功能,将环境变量分配给命令,但它实现了相同的目标。该$prefix变量在命令行的处理过程中被扩展,将 name=value 提供给env,谁将其传递给bash

  • 类似地,`$foo=bar bash -c ...` 不会工作,因为`$foo=bar` 不是变量赋值(无论`$foo` 的值是什么),因为`$foo=bar ` 不适合变量赋值的 `name=value` 模式。 (3认同)

ilk*_*chu 5

因为$prefix这不是作业。@Jeff 有更长的解释

\n\n

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

\n\n
$\xc2\xa0prefix() { hello=hi "$@"; }\n$ prefix bash -c \'echo "$hello"\'\nhi\n
Run Code Online (Sandbox Code Playgroud)\n\n

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

\n\n
$ foo() { foo=123 "$@"; }\n$ bar() { bar=456 "$@"; }\n$ foo bar bash -c \'echo "$bar $foo"\'\n456 123\n
Run Code Online (Sandbox Code Playgroud)\n