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

ash*_*gpu 266 shell echo environment-variables

如果我跑

export TEST=foo
echo $TEST
Run Code Online (Sandbox Code Playgroud)

它输出 foo。

如果我跑

TEST=foo echo $TEST
Run Code Online (Sandbox Code Playgroud)

它不是。如何在不使用导出或脚本的情况下获得此功能?

pet*_*rph 311

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

TEST=foo; echo $TEST
Run Code Online (Sandbox Code Playgroud)

它会起作用。

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

TEST=foo your-application
Run Code Online (Sandbox Code Playgroud)

shell 语法将其描述为在功能上等同于:

export TEST=foo
your-application
unset TEST
Run Code Online (Sandbox Code Playgroud)

有关详细信息,请参阅规范

有趣的是,该export命令会切换变量name的导出标志。因此,如果你这样做:

unset TEST
export TEST
TEST="foo"
Run Code Online (Sandbox Code Playgroud)

TEST即使在导出时未定义,也将被导出。但是进一步unset应该从中删除导出属性。

  • 同样的原因 - shell 在命令行执行之前扩展了 `$TEST`。一旦 `echo` 运行(另请注意,`echo` 通常会转换为 shell 内置命令而不是 `/bin/echo`),它会看到在其环境中设置的变量。然而,`echo $TEST` 并没有告诉`echo` 从它的环境中输出变量`TEST` 的内容。它告诉 shell 运行 `echo`,参数是当前在名为 `TEST` 的变量中的任何内容 - 这是两个非常不同的东西。 (8认同)
  • /usr/bin/env 怎么样?这也不起作用,你知道为什么吗? (2认同)

Sté*_*las 68

我怀疑你想让shell变量有一个有限的范围,而不是环境变量。环境变量是执行命令时传递给命令的字符串列表。

var=value echo whatever
Run Code Online (Sandbox Code Playgroud)

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

如果你写过

var=value sh -c 'echo "$var"'
Run Code Online (Sandbox Code Playgroud)

那将是另一回事。在这里,我们传递var=valuesh命令,并且sh碰巧使用了它的环境。Shell 将从它们的环境中接收到的每个变量转换为一个 shell 变量,因此接收到的var环境变量sh将被转换为一个$var变量,当它在该echo命令行中扩展它时,它将变成echo value. 因为环境默认是继承的,echo也会var=value在它的环境中接收(或者如果它被执行了),但同样,echo不关心环境。

现在,如果我怀疑您想要的是限制 shell 变量的范围,那么有几种可能的方法。

便携(Bourne 和 POSIX):

(var=value; echo "1: $var"); echo "2: $var"
Run Code Online (Sandbox Code Playgroud)

上面的 (...) 启动一个子 shell(在大多数 shell 中是一个新的 shell 进程),所以在那里声明的任何变量只会影响那个子 shell,所以我希望上面的代码输出“1:值”和“2:”或“2:what-var-was-set-to-before”。

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

f() {
  local var
  var=value
  echo "1: $var"
}
f
echo "2: $var"
Run Code Online (Sandbox Code Playgroud)

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

(){ local var=value; echo "1: $var"; }; echo "2: $var"
Run Code Online (Sandbox Code Playgroud)

或者:

function { local var=value; echo "1: $var"; }; echo "2: $var"
Run Code Online (Sandbox Code Playgroud)

使用 bash 和 zsh(但不是 ash、pdksh 或 AT&T ksh),这个技巧也有效:

var=value eval 'echo "1: $var"'; echo "2: $var"
Run Code Online (Sandbox Code Playgroud)

一个可以在更多 shell ( dash, mksh, yash) 中运行但不能运行的变体zsh(除非在sh/ksh仿真中):

var=value command eval 'echo "1: $var"'; echo "2: $var"
Run Code Online (Sandbox Code Playgroud)

(在 POSIX shell 中command的特殊内置eval函数(此处)前使用会消除它们的特殊性(此处,它们中的变量赋值在它们返回后仍然有效))


¹ 严格来说,这并不完全正确。一些实现会关心本地化环境变量(LANG, LOCPATH, LC_*...),GNU 实现会关心POSIXLY_CORRECT环境变量(env echo --versionPOSIXLY_CORRECT=1 env echo --versionGNU 系统相比)。

  • 就我而言,这是正确的解决方案。我不希望变量“var”像在接受的答案中那样污染环境。 (2认同)

Oli*_*ver 20

您做对了,但是 bash 语法很容易被误解:您可能认为这echo $TEST会导致echo获取TESTenv var 然后打印它,但事实并非如此。所以给出

export TEST=123
Run Code Online (Sandbox Code Playgroud)

然后

TEST=456 echo $TEST
Run Code Online (Sandbox Code Playgroud)

涉及以下顺序:

  1. shell解析了整个命令行并执行了所有的变量替换,所以命令行变成了

    TEST=456 echo 123
    
    Run Code Online (Sandbox Code Playgroud)
  2. 它创建在命令之前设置的临时变量,因此它保存当前值TEST并用 456 覆盖它;命令行现在是

    echo 123
    
    Run Code Online (Sandbox Code Playgroud)
  3. 它执行剩余的命令,在这种情况下将 123 打印到标准输出(因此剩余的 shell 命令甚至不使用 的临时值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
>>
Run Code Online (Sandbox Code Playgroud)


pra*_*tri 7

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

TEST=foo && echo $TEST
Run Code Online (Sandbox Code Playgroud)

  • 在这种情况下,`TEST=foo` 作为一个单独的语句运行 - 它不仅仅是在 `echo` 的上下文中设置的。 (8认同)

归档时间:

查看次数:

438652 次

最近记录:

4 年,6 月 前