Bash 带子函数的变量作用域
我今天读了这篇文章 “局部只能在函数中使用;它使变量名具有 可视范围仅限于该函数及其子函数。” ABS指南作者认为这种行为是一个bug 我想出了这个剧本Bash 带子函数的变量作用域,bash,scope,local-variables,Bash,Scope,Local Variables,我今天读了这篇文章 “局部只能在函数中使用;它使变量名具有 可视范围仅限于该函数及其子函数。” ABS指南作者认为这种行为是一个bug 我想出了这个剧本 begin () { local foo alpha } alpha () { foo=333 bar=444 bravo } bravo () { printf 'foo %3s bar %s\n' "$foo" "$bar" } begin bravo 输出 foo 333 bar 444 foo bar 4
begin () {
local foo
alpha
}
alpha () {
foo=333 bar=444
bravo
}
bravo () {
printf 'foo %3s bar %s\n' "$foo" "$bar"
}
begin
bravo
输出
foo 333 bar 444
foo bar 444
正如你们所看到的,因为我没有本地条码,所以它泄露到了全球
范围问题:
- 子函数可用的局部变量实际上是一个bug,还是 那只是他的意见
- Bash是否有一种方法可以标记所有本地内容,类似于
标记的方式 所有的东西都要出口吗set-a
- 如果不能做到这一点,Bash是否有办法检查这些泄露的全球信息 变量
declare-g
强制设置全局,但是无法强制Bash取消对它的引用,或者测试它是否已设置,这使得该功能的实用性非常有限
这很有希望清楚地说明这个问题
f() {
local x="in x" # Assign a local
declare -g x=global # Assign a global
declare -p x # prints "in x"
unset -v x # try unsetting the local
declare -p x # error (x is invisible)
}
f
declare -p x # x is visible again, but there's no way to test for that before now.
如果不能做到这一点,Bash是否有办法检查这些泄漏的全局变量
不,Bash有一个未记录的概念,称为“隐藏变量”,这使得在不干扰变量的情况下无法测试是否设置了局部变量
这个测试演示了一个隐藏变量以及内置变量的范围敏感特性
Bash可以使用declare-g
强制设置全局,但是无法强制Bash取消对它的引用,或者测试它是否已设置,这使得该功能的实用性非常有限
这很有希望清楚地说明这个问题
f() {
local x="in x" # Assign a local
declare -g x=global # Assign a global
declare -p x # prints "in x"
unset -v x # try unsetting the local
declare -p x # error (x is invisible)
}
f
declare -p x # x is visible again, but there's no way to test for that before now.
明确地说,动态范围几乎总是被认为是语言设计的一个缺陷。在Bash(和大多数其他shell)的情况下,它是故意的,而不是偶然的“bug”。在Bash(和大多数其他shell)的例子中,这是故意的,不是偶然的“bug”。@StevenPenny我误解了吗?变量不能以意外地将局部设置为全局的方式“泄漏”(除了使用
declare-g
)。有意设置父作用域中声明的变量的最常见原因是模拟按引用传递,而无法测试本地化变量或保证引用特定实例这一事实是一个难题。如果目的是设置一个全局变量,那么同样的问题也适用declare-g
保证设置了正确的实例,但设置后无法直接引用全局实例。没错,unset
在脚本完成时剥离了所有层。当第一次点击案例的最后一个分支时,x
设置在第一个范围内,但测试(使用${x+word}
)显示相反的结果。在从子作用域中实际取消设置x之前,无法区分x是否被设置。这正是您在示例问题中试图避免(或检测)的问题。代码/注释是正确的。如果bash的版本早于4.2alpha,那么就没有声明-g
。它只是用来示范的。在调用f
之前定义全局函数也会产生同样的效果,所以我用bash4.3再次尝试了这一点。函数之外只有x
的全局值可用,那么问题出在哪里?@StevenPenny这就是第一条注释中描述的declare-g
的陷阱(通常是动态范围的一个大问题)。declare-g
的唯一功能是允许无条件分配到全局作用域,即使在当前作用域的任何父级中设置了具有相同名称的本地作用域。它不会使该变量在当前范围内可用,直到您从第一个本地化该变量的函数返回,或者从最后一个本地化该变量的任何子范围调用unset
,直到所有具有冲突名称的局部变量都被取消设置为止。@StevenPenny我误解了吗?变量不能以意外地将局部设置为全局的方式“泄漏”(除了使用declare-g
)。有意设置父作用域中声明的变量的最常见原因是模拟按引用传递,而无法测试本地化变量或保证引用特定实例这一事实是一个难题。如果目的是设置一个全局变量,那么同样的问题也适用declare-g
保证设置了正确的实例,但设置后无法直接引用全局实例。没错,unset
在脚本完成时剥离了所有层。当洛杉矶