如何在命令行上设置环境变量并使它出现在命令中?


Answers:


179

这是因为Shell在实际运行命令之前在命令行中扩展了该变量,而那时该变量不存在。如果您使用

TEST=foo; echo $TEST

它会工作。

export将使变量出现在随后执行的命令的环境中(有关bash的工作原理,请参见help export)。如果只需要变量出现在一个命令的环境中,请使用您尝试过的方法,即:

TEST=foo your-application

1
/ usr / bin / env呢?那也不行,你知道为什么吗?
Benubird 2014年

5
相同的原因-shell在$TEST执行命令行之前将展开。一旦echo正在运行(也注意到,echo通常会转化为内置的命令,而不是外壳/bin/echo),它认为在其环境变量设置。但是,echo $TEST不要告诉要从其环境echo输出变量的内容TEST。它告诉外壳程序以echo参数作为当前运行的参数运行TEST-这是两个非常不同的东西。
彼得2014年

@peterph如果shell在实际运行命令之前在命令行中扩展了变量,那么为什么不将其扩展var=value sh -c 'echo "$var"'
折断

正如我在这里向您解释的:这是因为变量在双引号(例如"… $var …")内而不是单引号(例如'… $var …')内扩展。由于echo "$var"在单引号内,所以整个字符串将传递到new(sh -c)shell,而不会由外部交互式shell解释。…(续)
G-Man

(续)…正如igal昨天所说,有两轮解析–尽管我相信igal会误读您的问题。除了由父shell进行的解析外,没有两轮解析。进行两轮解析-一轮由外部交互式(父)外壳完成,一轮由new(sh -c)子外壳完成。
G-Man

39

我怀疑您想让shell变量具有有限的作用域,而不是环境变量。环境变量是执行时传递给命令的字符串的列表。

var=value echo whatever

您正在将var=value字符串传递给echo接收的环境。但是,echo它对环境列表不做任何事情,并且在大多数shell中无论如何echo都是内置的,因此不执行

如果你写过

var=value sh -c 'echo "$var"'

那将是另一回事。在这里,我们传递var=value给该sh命令,并且sh确实使用了它的环境。Shell将它们从环境中接收到的每个变量都转换为Shell变量,因此接收到的var环境变量sh将被转换为$var变量,并且在该echo命令行中对其进行扩展时,它将变为echo value。因为默认情况下环境是继承的,所以echo也会var=value在其环境中接收(或将在环境中执行),但是同样,echo它并不关心环境。

现在,如果我怀疑要限制外壳程序变量的范围,则有几种可能的方法。

可移植(Bourne和POSIX):

(var=value; echo "1: $var"); echo "2: $var"

上面的(...)启动了一个子shell(大多数shell中都是一个新的shell进程),因此在那里声明的任何变量都只会影响该子shell,因此我希望上面的代码输出“ 1:value”和“ 2:”或“ 2:之前设置的任何变量”。

对于大多数类似于Bourne的shell,您可以使用函数和内置的“ local”:

f() {
  local var
  var=value
  echo "1: $var"
}
f
echo "2: $var"

使用zsh,可以使用内联函数:

(){ local var=value; echo "1: $var"; }; echo "2: $var"

要么:

function { local var=value; echo "1: $var"; }; echo "2: $var"

对于bash和zsh(但不适用于ash,pdksh或AT&T ksh),此技巧也适用:

var=value eval 'echo "1: $var"'; echo "2: $var"

一个变种,在几个弹作品(dashmkshyash),但不zsh(除非sh/ ksh模拟):

var=value command eval 'echo "1: $var"'; echo "2: $var"

(在POSIX shell中command的特殊内置eval函数(here )前面使用会删除它们的特殊性(此处返回的变量分配在返回后仍然有效))


对我而言,这是正确的解决方案。我不希望变量'var'像接受的答案那样污染环境。
kronenpj

6

您做得正确,但是bash语法很容易被误解:您可能认为echo $TEST导致echo获取TESTenv var的原因然后将其打印出来,但事实并非如此。因此给定

export TEST=123

然后

TEST=456 echo $TEST

涉及以下顺序:

  1. Shell会解析整个命令行并执行所有变量替换,因此命令行变为

    TEST=456 echo 123
  2. 它在命令之前创建了temp vars,因此保存了的当前值TEST并用456覆盖了它;命令行现在

    echo 123
  3. 它执行剩余的命令,在这种情况下,将123打印到stdout(因此,剩下的shell命令甚至没有使用temp的值TEST

  4. 它恢复了 TEST

请改用printenv,因为它不涉及变量替换:

>> export TEST=123
>> printenv TEST
123
>> TEST=456 printenv TEST
456
>> printenv TEST && TEST=456 printenv TEST && TEST=789 printenv TEST && printenv TEST
123
456
789
123
>>

我发现+1 printenv对测试/概念验证很有帮助(行为与脚本相反,而不是echo
Daryn

5

您可以使用以下方法来使其工作:

TEST=foo && echo $TEST

6
在这种情况下,TEST=foo是作为单独的语句运行的-它不仅是在的上下文中设置的echo
codeforester
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.