bash - 嵌套函数调用中的变量赋值意外地更改了调用者作用域中的局部变量

标签 bash function scope zsh

<支持> 编者注:
也许以下摘自 OP 自己的答案,更好地说明了令人惊讶的行为:
f() { 本地 b=1; G; echo $b; }; g() { b=2; }; f# -> '2'
即,g() 能够修改 f()local $b 变量。


在 Zsh 和 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-}"

关于bash - 嵌套函数调用中的变量赋值意外地更改了调用者作用域中的局部变量,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/41770139/

相关文章:

linux - 程序参数中参数扩展的奇怪行为

mysql - sed 从 sql 转储中删除 DEFINER

linux - 如何为 php 文件安排 cronjob?

Javascript随机化数组,而起始位置没有元素

c++ - 超出范围的局部变量......我认为

python - Cronjob - 如何输出 stdout 并忽略 stderr

C++ const 成员函数

Javascript 闭包 - 无法在 IIFE 函数中保存 "count' 的副本

javascript复制一个变量以在函数中使用

javascript - jQuery UI 事件范围问题