本文讨论 linux shell 脚本函数中, 使用 local 定义的变量的 “穿透性”
先看代码:
way1(){
funA(){
local var_a="hello funA"
funB
echo $var_a
}
funB(){
var_a="modified by funB"
}
funA
echo "global: <$var_a>"
}
way1
运行结果:
in funB, var_a=
modified by funB
global: <>
说明, 在被调用函数内部, 可以自由访问(读写)上级函数定义的局部变量. 在 funA 调用结束, 打印 $var_a 为空, 说明 funB 修改的的确不是全局变量.
那这有什么作用呢?
仅仅这样使用上级函数的变量, 缺乏灵活性, 我们需要的是”动态”, 演变成所谓的”输出参数”, 例如:
way2(){
funA(){
local va="hello, funA"
funB va # 注意不是 $va
echo "result:{$va}"
}
# $1: 要修改的变量名
funB(){
local v_name=$1
eval "$v_name=\"modified bu funB\""
}
funA
}
way2
运行结果:
result:{modified bu funB}
说明, 我们成功实现了输出参数. 类似于”指针”, 这在一些特定的场景, 特别是无法使用 echo printf 返回值, 或者是必须回避创建子 shell等情况下, 可能会起到出奇制胜的效果.
注意使用 eval 赋值时, 两侧双引号的转义斜杆是必须的.
【分析】
所谓 “局部变量” 的穿透, 本质上是同一进程中变量的共享, 所以, 如果上述的 funB 调用, 创建了子 shell, 默认是不穿透的, 例如, 为了 funB 的返回值, 不得不采用的调用形式: $(funB va)
way3(){
funA(){
g_var="global var in funA"
local va="hello, funA"
local temp=$(funB va) # 注意不是 $va
echo "result:{$va}, temp={$temp}"
}
# $1: 要修改的变量名
funB(){
g_var="no, this is in funB"
local v_name=$1
eval "$v_name=\"modified bu funB\""
echo 100
}
funA
echo "global: <$var_a>, g_var=<$g_var>"
}
way3
测试结果:

即无法修改上级函数中的局部变量 va, 其实, 即使上级函数中定义的全局变量(g_var)也无法修改, 因为两个 shell 是隔离的.