shell变量失效主因是作用域混淆:未export的变量不被子进程继承;./执行脚本启子shell,变量不回传父shell;source则在当前shell执行;函数内变量默认全局,需local声明局部;()和|也会创建子shell导致变量不可见。

Shell 变量失效,通常不是“变量丢了”,而是作用域没搞清——子进程无法修改父进程的变量,导出(export)与否、脚本执行方式(source vs ./script.sh)、函数内声明方式,都会直接影响变量是否“可见”或“可继承”。
变量默认只在当前 Shell 进程有效
在交互式 Shell 中直接赋值:name="alice",这个变量仅存在于当前 Shell。一旦你运行一个外部命令或新脚本(如 ./other.sh),系统会 fork 出一个子进程,它**不继承未导出的变量**。
-
name="alice"; echo $name→ 能输出alice -
name="alice"; ./other.sh→other.sh里echo $name输出为空 - 解决方法:加
export name或写成export name="alice"
执行脚本的方式决定变量能否影响当前环境
用 ./script.sh 是启动子 Shell,里面所有变量赋值、export 都不会回到父 Shell;而 source script.sh(或 . script.sh)是在当前 Shell 中逐行执行,变量生效且持久。
-
./setvar.sh内有PATH="/new/bin:$PATH"→ 当前终端的PATH不变 -
source setvar.sh→ 当前 Shell 的PATH立即更新 - 常见误操作:把
export JAVA_HOME=...写进脚本却用./执行,结果java -version仍报错
函数内部变量默认是全局的,除非显式声明为局部
在函数里直接写 tmp="hello",这个变量会成为全局变量,可能意外覆盖同名变量;想限定作用域,必须用 local(Bash)或 declare。
-
myfunc() { msg="done"; }; myfunc; echo $msg→ 输出done(已污染全局) -
myfunc() { local msg="done"; }; myfunc; echo $msg→ 输出为空(安全) -
local只在 Bash/Zsh 中有效,POSIX sh 不支持,跨 shell 兼容需避免依赖
子 Shell 括号 (...) 和管道 | 也会创建独立作用域
用圆括号包裹命令会新建子 Shell,其中变量变化不出去;管道右侧命令也运行在子 Shell 中,无法通过变量传值。
-
(count=100); echo $count→ 仍输出原值(比如空或旧值) -
echo "a b" | while read x y; do result="$x-$y"; done; echo $result→ 输出为空 - 替代方案:用
while重定向代替管道,或把逻辑放进$(...)命令替换中捕获输出










