编者注:
也许以下内容取自OP自己的答案,更好地说明了令人惊讶的行为:
f() { local b=1; g; echo $b; }; g() { b=2; }; f # -> '2'
即,g()
能够修改f()
的局部 $b
变量.
在岩组和Bash,如果我有以下功能f() { a=1; g; echo $a; }
及以下功能g() { a=2; }
,当我跑f
,我得到下面的输出,而不是预期:
$ f
2
无论如何要禁用从函数到函数的这个变量渗透?
我正在研究一个相当大而重要的bash/zsh脚本,它在各种函数中使用了大量的变量; 许多这些功能依赖于更大的主功能,但是由于变量通过一些相当不幸和意外的行为而流失,并且错误已经成为最重要的,阻止我自信地进一步发展,因为我想首先解决这个奇怪的问题.
我甚至尝试使用local
本地化变量,但效果仍然存在.
编辑:请注意,我的问题不是关于如何使用局部变量来防止变量渗透或关于局部变量如何工作,如何设置局部变量,如何为已经声明的局部变量分配新值,或者任何一个废话:它是关于如何防止变量渗入调用者/被调用函数的范围.
使用local
创建不从父作用域继承的变量.
有一些有用的东西需要补充.
如果声明的函数调用另一个函数,则将继承(并且可以修改)局部变量.因此,local
保护对范围内较高的同名变量的更改,但不会低于范围中的变量.该local
声明必须因此在每个级别中使用,当然,除非你真的想改变父范围值.这与大多数编程语言的作用相反,并且具有优势(快速和脏的数据共享),但却难以调试失败模式.
可以导出局部变量local -x
以使其可用于子流程(非常有用),或者在创建时可以只读取local -r
.
一个很好的技巧是你可以在创建时使用从父作用域继承的值初始化变量:
local -r VAR="$VAR"
如果像我一样,总是使用set -u
以避免静默使用未初始化的变量,并且无法确定已经分配了变量,那么如果未在父作用域中定义,则可以使用此值将其初始化为空值:
local -r VAR="${VAR-}"