linux shell中全局变量默认存在且函数内可直接读写,但需export才能传给子进程;局部变量必须用local显式声明于函数内,否则函数内赋值仍为全局。

Linux Shell中实现全局变量与局部变量的隔离,关键不在“命名”,而在“声明方式”和“作用范围控制”。Shell默认不自动区分函数内外变量的作用域,必须靠显式语法干预。
全局变量:默认存在,但不自动传给子进程
在脚本顶层(函数外)直接赋值的变量,如 name="Alice",就是全局变量。它在整个脚本生命周期内都可读可写,函数内部能直接访问、也能直接修改——改完就是真改了,无需 global 关键字。
但它有个重要限制:不会自动传递给子进程(比如 bash -c 'echo $name' 会输出空)。若需子进程继承,必须用 export name 显式导出,此时它才成为环境变量。
局部变量:必须用 local 显式声明
Shell函数里定义的变量,默认仍是全局的——这点和大多数编程语言相反。例如:
-
myfunc() { tmp="hello"; }→tmp在函数外也能被echo $tmp读到 -
myfunc() { local tmp="hello"; }→tmp函数外完全不可见,且同名全局变量不受影响
local 只能在函数内部使用;放在脚本顶层会报错。建议养成习惯:函数内所有临时变量都加 local 声明。
避免意外覆盖:明确意图,分清用途
函数内既要读全局配置、又要写临时数据时,容易混淆。实用做法包括:
- 读取全局变量直接引用,如
echo $CONFIG_DIR - 新建仅函数内用的变量,统一用
local var=value - 确需在函数内创建新全局变量,用
declare -g newvar=value(比裸赋值更清晰) - 检查变量是否已设置:
[ -v myvar ] && echo "set" - 清理不用的变量:
unset myvar(只对当前 shell 生效)
特别注意子Shell带来的“假局部”陷阱
管道 |、命令替换 $(...)、小括号 (...)、后台任务 & 都会触发子Shell。在这些结构里赋值的变量,哪怕没加 local,也只在子Shell内有效,父Shell完全看不到——这不是作用域问题,而是进程隔离。
例如:echo "123" | while read line; do val=$line; done; echo $val 输出为空,因为 val 被赋值在子Shell里。











