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


11

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

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
您可以使用env代替evalIIRC,它更安全,但速度更慢。
wjandrea

Answers:


14

我怀疑这是吸引您的顺序的一部分:

不是变量分配或重定向的单词将被扩展(请参阅Shell Expansions)。如果扩展后还剩下任何单词,则将第一个单词作为命令的名称,并将其余单词作为参数

这是来自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,请考虑wjandrea的建议env

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

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


3
同样,$foo=bar bash -c ...由于$foo=bar不是变量赋值(无论是的值$foo),还是因为$foo=bar不适合name=value变量赋值的模式,所以将不起作用。
muru

3

因为$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
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.