程序退出后,状态为!= 0(set -e)时执行EXIT陷阱的Bash函数作用域状态

问题描述 投票:5回答:1

在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 local readonly bash-trap
1个回答
0
投票

这是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_context1,即与func_two中的值相同。当脚本尝试设置var时,Bash查看在此上下文中定义的名称,并发现var已经存在,位于func_two的左侧。

我在调试器中确认了这一点,并且还具有一种解决方法:如果添加中间函数调用,脚本将起作用,因为现在在func_one中,variable_context2,而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)是不够的。

© www.soinside.com 2019 - 2024. All rights reserved.