在bash函数中声明局部变量使该变量仅在函数本身及其子级内部可见,因此如果我运行:
#!/bin/bash
set -e
func_one() {
echo "${var}"
}
func_two() {
local -r var="var from func_two"
func_one
}
func_two
输出为:
var from func_two
即使var变量被声明为本地变量,并且func_two内部的只读变量也可以从函数func_one访问。在后者中,可以声明一个具有本地和只读名称的变量:
#!/bin/bash
set -e
func_one() {
local -r var="var from func_one"
echo "${var}"
}
func_two() {
local -r var="var from func_two"
func_one
}
func_two
输出为:
var from func_one
如果从退出陷阱中调用func_one,也会发生同样的情况:
func_one() {
local -r var="var from func_one"
echo "${var}"
}
func_two() {
local -r var="var from func_two"
trap 'func_one' EXIT
echo "${var}"
}
func_two
运行我收到的代码:
var from func_two
var from func_one
但是,如果在错误后执行EXIT陷阱(如果命令以非零状态退出,则set -e选项会使脚本立即退出)。似乎无法在func_one:
中重新分配var变量func_one() {
local -r var="var from func_one"
echo "${var}"
}
func_two() {
local -r var="var from func_two"
trap 'func_one' EXIT
echo "${var}"
false
}
func_two
运行我收到的代码:
var from func_two
local: var: readonly variable
有人可以向我说明为什么会这样吗?预先谢谢你。
这是Bash中的错误。
最初将func_one
安装为出口处理程序时,在func_two
返回之后,Bash在脚本末尾调用它。一切都很好。
[当您使用set -e
的组合并从false
调用func_one
时,Bash在调用false
之后(换句话说,在func_one
内)退出脚本,并调用退出处理程序。
Bash通过调用longjump
将代码ERREXIT
传递给顶级解析器,从而实现了“错误退出”。在处理这种情况的代码中,有一段注释表明脚本应该忘记正在执行的任何功能,这是通过将变量variable_context
设置为0
来完成的。看起来variable_context
是命名作用域堆栈的索引,并将其设置回0
会将其指向顶级全局作用域。
[下一步,Bash调用陷阱处理程序,后者调用func_one
。现在variable_context
为1
,即与func_two
中的值相同。当脚本尝试设置var
时,Bash查看在此上下文中定义的名称,并发现var
已经存在,位于func_two
的左侧。
我在调试器中确认了这一点,并且还具有一种解决方法:如果添加中间函数调用,脚本将起作用,因为现在在func_one
中,variable_context
是2
,而Bash看不到剩余的[C0 ]从var
中删除了:
func_two
显然在Bash代码中,展开函数调用栈实际上涉及到删除变量(有一个名为#!/bin/bash
set -e
func_one() {
local -r var="var from func_one"
echo "${var}"
}
func_intermediate() {
func_one
}
func_two() {
local -r var="var from func_two"
echo "${var}"
trap 'func_intermediate' EXIT
false
}
func_two
的函数);仅递减kill_all_local_variables
(或将其设置为variable_context
)是不够的。