通常,可以通过像这样添加前缀来为命令设置环境变量:
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