为什么可以在Bash函数中设置环境变量,而不能在脚本本身中设置

为什么可以在Bash函数中设置环境变量,而不能在脚本本身中设置,bash,Bash,为什么这样做有效: # a.sh setEnv() { export TEST_A='Set' } 如果没有: # b.sh export TEST_B='Set' 例: 我理解为什么运行脚本不起作用,以及如何使它起作用(source b.sh等),但我很好奇为什么这个函数起作用。 这在OSX上是很重要的。执行函数本身并不会像b.sh那样启动新进程 从手册页(强调最后一句): 函数 一个shell函数,如上所述在shell语法中定义, 存储一系列用于以后执行的命令。当一个人的名字 s

为什么这样做有效:

# a.sh
setEnv() {
    export TEST_A='Set'
}
如果没有:

# b.sh
export TEST_B='Set'
例:

我理解为什么运行脚本不起作用,以及如何使它起作用(
source b.sh
等),但我很好奇为什么这个函数起作用。
这在OSX上是很重要的。

执行函数本身并不会像
b.sh
那样启动新进程

从手册页(强调最后一句):

函数
一个shell函数,如上所述在shell语法中定义,
存储一系列用于以后执行的命令。当一个人的名字
shell函数用作简单的命令名,即命令列表
执行与该函数名关联的**函数被执行
在当前shell的上下文中;没有创建新的进程来
解释它们(与执行shell脚本相比)**

您需要理解寻找和执行脚本之间的区别

  • 寻源从调用脚本的父shell运行脚本;所有环境变量都将保留,直到父shell终止(终端关闭,或变量重置或取消设置),而

  • Execute从父shell派生一个新shell,这些变量(包括
    导出
    变量)仅保留在子shell的环境中,并在脚本终止时销毁

i、 e.在第一种情况下创建的用于保存变量的子外壳(假设它是一个环境)未分配在单独的子环境的范围内,而是添加到父环境(例如,假设一个额外的内存单元,由父环境维护)中,该环境一直保持到会话打开为止。但是,想象一个简单的类比,执行一个脚本就是调用一个函数,该函数的变量存储在堆栈中,而堆栈在函数调用结束时失去了作用域。类似地,forkedshell的环境在终止时会失去作用域

因此,归根结底,即使你有一个函数来导出你的变量,如果你没有把它导出到当前的shell中,只是简单地执行它,变量就不会被保留;i、 e

# a.sh
setEnv() {
    export TEST_A='Set'
}
如果你在shell中运行它

bash script.sh    # unlike/NOT source script.sh
env | grep TEST_A
                  # empty
我理解为什么运行脚本不起作用,以及如何使它起作用(
source b.sh
etc)

因此,您已经了解了这样一个事实,即直接在子进程中执行
b.sh
,其对环境的更改基本上不会对当前进程(shell)可见,而不会在当前(shell)进程中定义
TEST_b
,因此我们可以将此场景从图中去掉

我很好奇为什么这个函数会起作用

  • 当您
    source
    一个脚本时,您在当前shell的上下文中执行它-粗略地说,这就像您在提示符下直接键入了脚本的内容:环境的任何更改,包括特定于shell的元素,如shell变量、别名、函数、,对当前外壳可见

  • 因此,在执行
    source a.sh
    之后,函数
    setEnv
    现在在当前shell中可用,并调用它执行
    export TEST\u a='Set'
    ,该函数在当前shell中定义环境变量
    TEST\u a
    (随后创建的子进程将看到它)

  • 也许您的误解是关于什么地址:在类似POSIX的shell中,函数在当前shell中运行,而脚本(在没有
    源代码的情况下运行)则为其创建子进程

这是在OSX上,如果这很重要的话


在这种情况下不是这样,因为只使用内置于
bash
本身的功能。

当运行脚本时,它会创建一个子shell,变量将在那里定义,但不会在父脚本中定义。函数调用仍在当前shell中。你也可以
source
另一个脚本。对称地对待脚本,它就会工作<代码>源代码b.sh
然后是
env | grep TEST_b
就可以了。如果您没有source
a.sh
,您将无法运行该函数。这都是关于子shell(运行
b.sh
会创建一个新的shell来设置它的环境),而不是(使用
source
不会创建一个新的shell)。他承认在没有
source
的情况下运行脚本是他的问题所在。同意@chepner:在这种情况下,让OP知道它们之间的区别将使他
source
第二个脚本也正确吗?你认为我应该添加一些其他信息吗?问题的关键似乎是为什么运行一个函数而运行一个脚本却不起作用。@chepner:这会让答案更好吗?有什么理由取消投票吗?尽量添加复杂的细节。如果你能让我知道还有什么遗漏,我很乐意补充。
bash script.sh    # unlike/NOT source script.sh
env | grep TEST_A
                  # empty