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