Bash中内联变量赋值和常规赋值有什么区别?

37

什么是以下内容之间的区别:

prompt$   TSAN_OPTIONS="suppressions=/somewhere/file" ./myprogram

prompt$   TSAN_OPTIONS="suppressions=/somewhere/file"
prompt$   ./myprogram
Thread-Sanitizer库给出了第一种情况,说明如何让他们的库(在我的程序中使用)读取选项中给定的文件。我阅读了它,并假设它应该是两个不同的行,因此将其作为第二种情况运行。

在第二种情况下,库不使用文件,其中环境变量和程序执行位于两行。

有什么区别吗?

奖励问题:第一种情况怎么可以没有错误地运行?它们之间难道不应该有分号或者&&吗?这个问题的答案很可能回答了我的第一个问题...

2个回答

40
格式为VAR=value command的命令设置变量VAR在命令command的环境中的值为value。相关规范详见Simple Commands,具体而言:

否则,变量赋值将被导出到命令的执行环境,并且除了步骤4执行时所进行的扩展之外,不会影响当前执行环境。

格式为VAR=value; command的命令设置shell变量VAR,然后作为子进程运行command。子进程不知道在shell进程中设置的变量。

进程将变量导出(提示一下)以供子进程查看的机制是在运行子进程之前在其环境中设置它们。做这件事的shell内置命令是export,这就是为什么经常可以看到export VAR=valueVAR=value; export VAR的原因。

您正在讨论的语法是类似于以下内容的简写形式:

VAR=value
export VAR
command
unset -v VAR

完全不使用当前进程环境。


啊,好的,谢谢!不过我有点困惑,因为如果我没有使用export,只是执行"CC=xyz"或者"CXX=xyz++",cmake也会识别到这些变化。按理说,它不应该这样才对吧?或者说,当一个环境变量被导出时,它是通过引用而不是值来导出的,所以可能有一个启动脚本在我不知道的情况下导出了CC和CXX。那么如果我改变它们,就可以生效了吗? - user1902689
2
正确,export 标记的是 变量 被导出而不是当前值。因此,即使您更改了值,您只需要导出一次变量。 - Etan Reisner
2
你可以运行 export -pdeclare -x 命令来查看当前导出变量列表(以及它们的当前值)。 - Etan Reisner

29

为了补充Etan Reisner的有用答案:

重要的是要区分shell变量和environment变量:

注意: 以下适用于所有POSIX兼容的shell; bash-特定的扩展标记如此。

Shell变量是一个仅限于定义它的shell的构造,(除了子shell,它们会获得自己的当前shell变量副本
而一个环境变量则被当前进程(shell)创建的任何子进程继承,无论该子进程是否本身是shell。
注意,全部大写的变量名仅应用于环境变量.

无论哪种方式,子进程只会继承变量的副本,其修改(由子进程)不会影响父进程

  • 所有环境变量也是shell变量(由shell确保),
  • 反之不成立: shell变量不是环境变量,除非显式指定或继承为环境变量 - 此称为导出
    • 请注意,默认情况下关闭的-a shell选项(使用set -a设置,或作为命令行选项传递给shell本身)可用于自动导出所有shell变量。

因此,

  • 您通过分配隐式创建的任何变量,例如: TSAN_OPTIONS="suppressions=/somewhere/file" - 仅为shell变量,而不是环境变量,
  • 除非 - 可能会造成混淆的是 - 直接在命令前面添加 - 例如 TSAN_OPTIONS="suppressions=/somewhere/file" ./myprogram - 在这种情况下,它们仅是环境变量,只对该命令有效。
    • 这就是Etan答案描述的内容。

在以下情况下,shell变量也成为环境变量:

  • 基于shell本身继承的环境变量,例如$ HOME
  • 使用export varName[=value]或在bash中也可以使用declare -x varName[=value]显式创建的shell变量。
    • 相比之下,在bash中,不带-x使用declare或在函数中使用local会创建一个简单的shell变量
  • 在默认情况下启用-a shell选项时隐式创建的shell变量(有限制)

一旦将shell变量标记为已导出 - 即标记为

export TSAN_OPTIONS  # creates shell variable *and* corresponding environment variable

# ...

TSAN_OPTIONS="suppressions=/somewhere/file" # updates *both* the shell and env. var.

  • export -p 命令会打印所有的环境变量。
  • unset [-v] MYVAR 命令会取消定义shell变量$MYVAR,并且如果适用的话也会将其作为环境变量移除。
  • bash 中:
    • 你可以使用 export -n MYVAR 取消导出一个指定的变量,但不会同时取消其作为 shell 变量的定义,这会将MYVAR 从环境变量中移除,但保留其当前值作为 shell 变量。
    • declare -p MYVAR 命令会打印变量$MYVAR的当前值和属性;如果输出以 declare -x 开头,则表示 $MYVAR 已导出(是一个环境变量)。

1
这个回答确切地回答了任何可能存在的误解。 - S.B

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接