我对 bash
变量是否导出到子 shell 以及何时可以通过脚本访问它们感到困惑。到目前为止,我的经验让我相信 bash 变量会自动可供子 shell 使用。例如:
> FOO=bar
> echo $FOO
bar
> (echo $FOO)
bar
上面的内容似乎证明了 bash
变量可以在子 shell 中访问。
给定这个脚本:
#! /usr/bin/bash
# c.sh
func()
{
echo before
echo ${FOO}
echo after
}
func
据我了解,在当前 shell 上下文中调用脚本可以使其访问当前 shell 的变量:
> . ./c.sh
before
bar
after
如果我在没有“点空间”先例的情况下调用脚本...
> ./c.sh
before
after
...不是说脚本是在子shell中调用的吗?如果是这样,并且当前 shell 的变量确实可用于子 shell(正如我从第一个代码块推断的那样),为什么 $FOO
不可用于 c.sh
什么时候这样运行?
同样,为什么当 c.sh
在括号内运行时 $FOO
也不可用 - 我理解这意味着在子 shell 中运行表达式:
> (./c.sh)
before
after
(如果这不会使这篇文章因太多问题而变得困惑:如果“./c.sh
”和“(./c.sh)
”两者在当前shell的子shell中运行脚本,两种调用方式有什么区别?)
最佳答案
(...)
运行...
在单独的环境中,使用子 shell 最容易实现的东西(并在 bash、dash 和大多数其他 POSIX-y shell 中实现)——也就是说,由 fork()
创建的子 shell ing 旧 shell,但不调用任何 execv
-家庭功能。因此,父级的整个内存状态都会被复制,包括未导出的 shell 变量。对于子 shell,这正是您通常想要的:只是父 shell 进程镜像的副本,而不是用新的可执行镜像替换,从而保持其所有状态。
考虑(. shell-library.bash; function-from-that-library "$preexisting_non_exported_variable")
举个例子:因为括号它 fork()
是一个子 shell,但它随后获取 shell-library.bash
的内容直接在该 shell 内,而不替换由该 fork()
创建的 shell 解释器具有单独的可执行文件。这意味着function-from-that-library
可以从父 shell 中看到非导出的函数和变量(如果是 execve()
'd,则看不到),并且启动速度更快一些(因为它不需要链接、加载等初始化一个新的 shell 解释器,就像 execve()
操作期间发生的那样);而且它对内存状态、shell 配置和进程属性(如工作目录)所做的更改不会修改调用它的父解释器(如果没有子 shell 并且它不是 fork()
,情况就会如此) 'd),因此父 shell 受到保护,不会受到库所做的配置更改的影响,这些更改可能会修改其后续操作。
./other-script
相比之下,运行 other-script
作为完全独立的可执行文件;在子 shell(不是子 shell!)被调用后,它不保留非导出变量。其工作原理如下:
- shell 调用
fork()
创造一个 child 。此时,子级甚至还复制了未导出的变量状态。 - child 打电话
./other-script >>log.out
,指示操作系统将其替换为open("log.out", O_APPEND)
的新实例。这次调用成功后,在子进程的PID下运行的进程是一个全新的程序,并且只有fdup()
ed 变量仍然存在。
关于bash - bash 变量何时导出到子 shell 和/或可由脚本访问?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/53312653/