在子 shell 中执行函数的变量范围
Scope of variables executing functions in a subshell
这是在子shell环境中执行命令时发生的情况:
该命令将运行复制到当前shell execution environment
"Variable assignments and builtin commands that affect the shell's environment do not remain in effect after the command completes" (quote)
示例:
#!/bin/sh
export TOTO=123
FOO=abc
(mycmd)
在这种情况下,mycmd 将能够读取 TOTO 但不能读取 FOO,并且 mycmd 实现的对这两个变量值的每个更改在当前 shell.
中将不可见
但是当我们用函数做同样的事情时会发生什么?
示例:
#!/bin/sh
export TOTO=123
FOO=abc
function (){
echo $TOTO
echo $FOO
TOTO=${TOTO}456
FOO=${FOO}def
}
(function)
echo $TOTO
echo $FOO
结果:
123
abc
123
abc
合理地,在子shell中执行的函数不能改变父shell中定义的变量的内容,另一方面它能够不加区别地读取所有变量即使它们没有被导出。
有人可以用更好的方式解释这种行为吗?
非常感谢指向一些参考的链接,因为我找不到任何相关信息。
您所看到的与功能无关。子外壳获取所有环境,甚至是未导出的变量。为了说明,让我们定义两个变量:
$ alpha=123
$ export beta=456
观察子 shell 可以访问两者:
$ (echo $alpha $beta)
123 456
但是,如果我们启动一个新进程,它只会看到导出的变量:
$ bash -c 'echo $alpha $beta'
456
文档
man bash
将子 shell 记录如下:
(list)
list is executed in a subshell environment (see COMMAND
EXECUTION ENVIRONMENT below). Variable assignments and builtin
commands that affect the shell's environment do not remain in effect
after the command completes. The return status is the exit status of
list.
如果我们去查看 "COMMAND EXECUTION ENVIRONMENT",我们发现它包括
shell parameters that are set by variable assignment or with set or inherited from the shell's parent in the environment.
换句话说,它包括变量无论是否它们已经导出。
如果我们进一步阅读,我们会发现这与 "a simple command other than a builtin or shell function." 形成对比,此类命令仅接收导出的变量。
这是一个简短的回答,希望能解释这些差异。它有两个函数myfun
和myfunlocal
。在 myfunlocal
中,toto
和 foo
都被声明为具有 toto
和 foo
的 local
副本,在函数中更新时不会反映回来在脚本的主体中,虽然 myfun
没有进行 local
重新声明,因此,对 toto
和 foo
的更改反映在主体中。但是,如果 (myfun)
在子 shell 中是 运行,则对 toto
和 foo
的更改不会反映在脚本的 main
主体中:
#!/bin/bash
function myfun {
printf "\n myfun - toto : %-6s foo : %s\n" \
"$toto" "$foo"
toto=lizard
foo=456
printf " myfun - toto : %-6s foo : %s\n" \
"$toto" "$foo"
}
function myfunlocal {
printf "\n myfunlocal - toto : %-6s foo : %s\n" \
"$toto" "$foo"
local toto=lizard
local foo=456
printf " myfunlocal - toto : %-6s foo : %s\n" \
"$toto" "$foo"
}
toto=dog
foo=123
printf "\n before myfunlocal : toto : %-6s foo : %s\n" "$toto" "$foo"
myfunlocal
printf "\n after myfunlocal : toto : %-6s foo : %s\n" "$toto" "$foo"
(myfun)
printf "\n after subshell myfun: toto : %-6s foo : %s\n" "$toto" "$foo"
myfun
printf "\n after simple myfun : toto : %-6s foo : %s\n\n" "$toto" "$foo"
输出
$ bash functionsubshell.sh
before myfunlocal : toto : dog foo : 123
myfunlocal - toto : dog foo : 123
myfunlocal - toto : lizard foo : 456
after myfunlocal : toto : dog foo : 123
myfun - toto : dog foo : 123
myfun - toto : lizard foo : 456
after subshell myfun: toto : dog foo : 123
myfun - toto : dog foo : 123
myfun - toto : lizard foo : 456
after simple myfun : toto : lizard foo : 456
这是在子shell环境中执行命令时发生的情况:
该命令将运行复制到当前shell execution environment
"Variable assignments and builtin commands that affect the shell's environment do not remain in effect after the command completes" (quote)
示例:
#!/bin/sh
export TOTO=123
FOO=abc
(mycmd)
在这种情况下,mycmd 将能够读取 TOTO 但不能读取 FOO,并且 mycmd 实现的对这两个变量值的每个更改在当前 shell.
中将不可见但是当我们用函数做同样的事情时会发生什么?
示例:
#!/bin/sh
export TOTO=123
FOO=abc
function (){
echo $TOTO
echo $FOO
TOTO=${TOTO}456
FOO=${FOO}def
}
(function)
echo $TOTO
echo $FOO
结果:
123
abc
123
abc
合理地,在子shell中执行的函数不能改变父shell中定义的变量的内容,另一方面它能够不加区别地读取所有变量即使它们没有被导出。
有人可以用更好的方式解释这种行为吗? 非常感谢指向一些参考的链接,因为我找不到任何相关信息。
您所看到的与功能无关。子外壳获取所有环境,甚至是未导出的变量。为了说明,让我们定义两个变量:
$ alpha=123
$ export beta=456
观察子 shell 可以访问两者:
$ (echo $alpha $beta)
123 456
但是,如果我们启动一个新进程,它只会看到导出的变量:
$ bash -c 'echo $alpha $beta'
456
文档
man bash
将子 shell 记录如下:
(list)
list is executed in a subshell environment (see COMMAND EXECUTION ENVIRONMENT below). Variable assignments and builtin commands that affect the shell's environment do not remain in effect after the command completes. The return status is the exit status of list.
如果我们去查看 "COMMAND EXECUTION ENVIRONMENT",我们发现它包括
shell parameters that are set by variable assignment or with set or inherited from the shell's parent in the environment.
换句话说,它包括变量无论是否它们已经导出。
如果我们进一步阅读,我们会发现这与 "a simple command other than a builtin or shell function." 形成对比,此类命令仅接收导出的变量。
这是一个简短的回答,希望能解释这些差异。它有两个函数myfun
和myfunlocal
。在 myfunlocal
中,toto
和 foo
都被声明为具有 toto
和 foo
的 local
副本,在函数中更新时不会反映回来在脚本的主体中,虽然 myfun
没有进行 local
重新声明,因此,对 toto
和 foo
的更改反映在主体中。但是,如果 (myfun)
在子 shell 中是 运行,则对 toto
和 foo
的更改不会反映在脚本的 main
主体中:
#!/bin/bash
function myfun {
printf "\n myfun - toto : %-6s foo : %s\n" \
"$toto" "$foo"
toto=lizard
foo=456
printf " myfun - toto : %-6s foo : %s\n" \
"$toto" "$foo"
}
function myfunlocal {
printf "\n myfunlocal - toto : %-6s foo : %s\n" \
"$toto" "$foo"
local toto=lizard
local foo=456
printf " myfunlocal - toto : %-6s foo : %s\n" \
"$toto" "$foo"
}
toto=dog
foo=123
printf "\n before myfunlocal : toto : %-6s foo : %s\n" "$toto" "$foo"
myfunlocal
printf "\n after myfunlocal : toto : %-6s foo : %s\n" "$toto" "$foo"
(myfun)
printf "\n after subshell myfun: toto : %-6s foo : %s\n" "$toto" "$foo"
myfun
printf "\n after simple myfun : toto : %-6s foo : %s\n\n" "$toto" "$foo"
输出
$ bash functionsubshell.sh
before myfunlocal : toto : dog foo : 123
myfunlocal - toto : dog foo : 123
myfunlocal - toto : lizard foo : 456
after myfunlocal : toto : dog foo : 123
myfun - toto : dog foo : 123
myfun - toto : lizard foo : 456
after subshell myfun: toto : dog foo : 123
myfun - toto : dog foo : 123
myfun - toto : lizard foo : 456
after simple myfun : toto : lizard foo : 456