bash 变量何时导出到脚本可访问的子 shell and/or?
When are bash variables exported to subshells and/or accessible by scripts?
我对 bash
变量是否导出到 subshells 以及脚本何时可以访问它们感到困惑。到目前为止,我的经验使我相信 bash 变量自动可用于子 shell。例如:
> FOO=bar
> echo $FOO
bar
> (echo $FOO)
bar
以上似乎表明 bash
变量在 subshell 中是可访问的。
鉴于此脚本:
#! /usr/bin/bash
# c.sh
func()
{
echo before
echo ${FOO}
echo after
}
func
我知道在当前 shell 上下文中调用脚本可以访问当前 shell 的变量:
> . ./c.sh
before
bar
after
如果我在没有 "dot space" 先例的情况下调用脚本...
> ./c.sh
before
after
...不就是在subshell中调用了脚本吗?如果是这样,而且当前 shell 的变量可用于 subshells 也是正确的(正如我从第一个代码块推断的那样),为什么 $FOO
不可用于c.sh
什么时候 运行 这样?
同样,当 c.sh
是 运行 在括号内时,为什么 $FOO
也不可用 - 我的理解是 运行 在子 [=44] 中表达=]:
> (./c.sh)
before
after
(如果这不会使 post 问题太多:如果“./c.sh
”和“(./c.sh)
”都 运行 子脚本当前shell的shell,这两种调用方式有什么区别?)
(...)
在单独的环境中运行 ...
,这是最容易实现的(并在 bash、破折号和大多数其他 POSIX-y shell 中实现s) 使用 subshell——也就是说,通过 fork()
ing 旧的 shell、 创建的 child 但不调用任何 execv
-族函数。因此,parent 的整个 in-memory 状态被复制,包括 non-exported shell 变量。对于子 shell,这正是您通常想要的:只是 parent shell 进程映像的副本,而不是用新的可执行映像替换,从而保留其所有状态到位。
以 (. shell-library.bash; function-from-that-library "$preexisting_non_exported_variable")
为例:由于 parens 它 fork()
是一个子 shell,但它随后获取 shell-library.bash
直接在 shell 中,而不用单独的可执行文件替换由 fork()
创建的 shell 解释器。这意味着 function-from-that-library
可以从 parent shell 中看到 non-exported 函数和变量(如果它是 execve()
则不能),并且是启动速度更快(因为它不需要 link、加载和初始化新的 shell 解释器,就像在 execve()
操作期间发生的那样);但它对 in-memory 状态、shell 配置和进程属性(如工作目录)所做的更改也不会修改调用它的 parent 解释器(如果有没有 subshell 并且它不是 fork()
'd),因此 parent shell 受到保护,不会被库进行可能修改其后续操作的配置更改。
相比之下,./other-script
将 other-script
作为完全独立的可执行文件运行;它 not 在 child shell 之后保留 non-exported 变量(这不是子 shell!) 已被调用。其工作方式如下:
- shell 调用
fork()
创建一个 child。此时,child 仍然复制了 non-exported 个变量状态。
- child 接受任何重定向(如果是
./other-script >>log.out
,child 会 open("log.out", O_APPEND)
然后 fdup()
描述符到 1
, 覆盖标准输出).
- child调用
execv("./other-script", {"./other-script", NULL})
,指示操作系统用other-script
的新实例替换它。本次调用成功后,child的PID下的进程运行是一个全新的程序,只有export
ed变量存活。
我对 bash
变量是否导出到 subshells 以及脚本何时可以访问它们感到困惑。到目前为止,我的经验使我相信 bash 变量自动可用于子 shell。例如:
> FOO=bar
> echo $FOO
bar
> (echo $FOO)
bar
以上似乎表明 bash
变量在 subshell 中是可访问的。
鉴于此脚本:
#! /usr/bin/bash
# c.sh
func()
{
echo before
echo ${FOO}
echo after
}
func
我知道在当前 shell 上下文中调用脚本可以访问当前 shell 的变量:
> . ./c.sh
before
bar
after
如果我在没有 "dot space" 先例的情况下调用脚本...
> ./c.sh
before
after
...不就是在subshell中调用了脚本吗?如果是这样,而且当前 shell 的变量可用于 subshells 也是正确的(正如我从第一个代码块推断的那样),为什么 $FOO
不可用于c.sh
什么时候 运行 这样?
同样,当 c.sh
是 运行 在括号内时,为什么 $FOO
也不可用 - 我的理解是 运行 在子 [=44] 中表达=]:
> (./c.sh)
before
after
(如果这不会使 post 问题太多:如果“./c.sh
”和“(./c.sh)
”都 运行 子脚本当前shell的shell,这两种调用方式有什么区别?)
(...)
在单独的环境中运行 ...
,这是最容易实现的(并在 bash、破折号和大多数其他 POSIX-y shell 中实现s) 使用 subshell——也就是说,通过 fork()
ing 旧的 shell、 创建的 child 但不调用任何 execv
-族函数。因此,parent 的整个 in-memory 状态被复制,包括 non-exported shell 变量。对于子 shell,这正是您通常想要的:只是 parent shell 进程映像的副本,而不是用新的可执行映像替换,从而保留其所有状态到位。
以 (. shell-library.bash; function-from-that-library "$preexisting_non_exported_variable")
为例:由于 parens 它 fork()
是一个子 shell,但它随后获取 shell-library.bash
直接在 shell 中,而不用单独的可执行文件替换由 fork()
创建的 shell 解释器。这意味着 function-from-that-library
可以从 parent shell 中看到 non-exported 函数和变量(如果它是 execve()
则不能),并且是启动速度更快(因为它不需要 link、加载和初始化新的 shell 解释器,就像在 execve()
操作期间发生的那样);但它对 in-memory 状态、shell 配置和进程属性(如工作目录)所做的更改也不会修改调用它的 parent 解释器(如果有没有 subshell 并且它不是 fork()
'd),因此 parent shell 受到保护,不会被库进行可能修改其后续操作的配置更改。
相比之下,
./other-script
将 other-script
作为完全独立的可执行文件运行;它 not 在 child shell 之后保留 non-exported 变量(这不是子 shell!) 已被调用。其工作方式如下:
- shell 调用
fork()
创建一个 child。此时,child 仍然复制了 non-exported 个变量状态。 - child 接受任何重定向(如果是
./other-script >>log.out
,child 会open("log.out", O_APPEND)
然后fdup()
描述符到1
, 覆盖标准输出). - child调用
execv("./other-script", {"./other-script", NULL})
,指示操作系统用other-script
的新实例替换它。本次调用成功后,child的PID下的进程运行是一个全新的程序,只有export
ed变量存活。