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

时间:2017-01-23 16:01:55

标签: bash

为什么这样做:

# a.sh
setEnv() {
    export TEST_A='Set'
}

这不是:

# b.sh
export TEST_B='Set'

例如:

> source a.sh
> setEnv
> env | grep TEST_A
TEST_A=Set
> b.sh
> env | grep TEST_B

我理解为什么运行脚本不起作用以及如何使其工作(source b.sh等),但我很好奇为什么功能有效。 如果重要的话,这是在OS X上。

3 个答案:

答案 0 :(得分:5)

您需要了解 采购 执行 脚本之间的区别。

  • Sourcing 从调用脚本的父shell运行脚本;保留所有环境变量,直到父shell终止(终端关闭,或者重置或重置变量),而

  • 执行从父shell分支新shell,包含export变量的变量仅保留在子shell的环境中,并在脚本终止时终止

即。在第一种情况下创建的用于保存变量的子shell(假设它是一个环境)不是在单独的子环境的范围内分配,而是仅在父项中添加(例如,想象一个额外的内存单元,由父级维护) )环境,直到你打开会话为止。但是,执行一个脚本,想象一个简单的类比,调用一个函数,其变量存储在堆栈中,在函数调用结束时松散范围。同样,分叉shell的环境在终止时会失去范围。

所以归结到这一点,即使你有一个函数export你的变量,如果你没有source它到当前shell并且只是明白execute它,不保留变量;即。

# a.sh
setEnv() {
    export TEST_A='Set'
}

如果你在shell中运行它

bash script.sh    # unlike/NOT source script.sh
env | grep TEST_A
                  # empty

答案 1 :(得分:4)

执行一个函数本身不会启动像b.sh这样的新流程。

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

FUNCTIONS
       A shell function, defined  as  described  above  under  SHELL  GRAMMAR,
       stores  a  series  of commands for later execution.  When the name of a
       shell function is used as a simple command name, the list  of  commands
       associated with that function name is executed.  **Functions are executed
       in the context of the current shell;  no  new  process  is  created  to
       interpret  them  (contrast  this with the execution of a shell script).**

答案 2 :(得分:3)

  

我理解为什么运行脚本不起作用以及如何使其运行(source b.sh等)

因此,您已经了解直接执行b.sh的事实 - 在子进程中,当前对环境的更改根本不可见 em> process(shell) - 当前(shell)进程中定义TEST_B,因此我们可以将这种情况从图片中删除。< / p>

  

我很好奇为什么功能有效。

  • 当您source脚本时,您在当前 shell的上下文中执行它 - 松散地说,就好像您直接键入了脚本的内容一样在提示符处:对环境的任何更改(包括特定于shell的元素,如 shell 变量,别名,函数)对当前shell都是可见的。

  • 因此,在执行source a.sh之后,函数setEnv现在在当前shell中可用,并且调用它执行export TEST_A='Set',它定义了环境变量TEST_A in 当前 shell(以及随后创建的子进程会看到它)。

  • 也许您的误解是chepner's helpful answer地址:在类似POSIX的shell中, 函数当前shell中运行 - 与脚本(在没有source的情况下运行时)相比,为其创建子进程

  

如果重要的话,这是在OS X上。

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