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

Par*_*ham 2 bash

为什么这样做:

# a.sh
setEnv() {
    export TEST_A='Set'
}
Run Code Online (Sandbox Code Playgroud)

当这不是:

# b.sh
export TEST_B='Set'
Run Code Online (Sandbox Code Playgroud)

例如:

> source a.sh
> setEnv
> env | grep TEST_A
TEST_A=Set
> b.sh
> env | grep TEST_B
Run Code Online (Sandbox Code Playgroud)

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

Ini*_*ian 8

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

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

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

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

所以,归结到这一点,即使你有一个功能,以export您的变量,如果你没有source它目前的外壳,只是说白execute了,变量没有保留; 即

# a.sh
setEnv() {
    export TEST_A='Set'
}
Run Code Online (Sandbox Code Playgroud)

如果你在shell中运行它

bash script.sh    # unlike/NOT source script.sh
env | grep TEST_A
                  # empty
Run Code Online (Sandbox Code Playgroud)


che*_*ner 6

执行一个函数本身并不会像启动一个新进程那样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).**
Run Code Online (Sandbox Code Playgroud)


mkl*_*nt0 5

我明白为什么运行脚本不起作用以及如何使它工作(source b.sh等)

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

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

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

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

  • 也许您的误解是围绕着chepner 有用的答案所解决的问题:在类似 POSIX 的 shell 中,函数当前 shell 中运行- 与脚本(在没有 时运行时source)形成对比,后者为其创建了一个子进程

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

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