为什么这样做:
# 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上.
您需要了解采购和执行脚本之间的区别.
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)
执行一个函数本身并不会像启动一个新进程那样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)
我明白为什么运行脚本不起作用以及如何使它工作(
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使用了自身内置的功能。