set -u 会立即报错“unbound variable”,仅对未声明变量生效,必须置于脚本首行或shebang后第二行,不检查空值,需配合 ${var:?} 防空、set -e 和 pipefail 防命令失败。

set -u 会立即报错“unbound variable”
脚本里写 $USER_NAME,但实际只定义了 USERNAME;或者拼错成 $CONF_DIR,而变量名其实是 CONFIG_DIR——这种错误默认不会报错,$CONF_DIR 被静默展开为空字符串,后续命令可能误删根目录、读错配置、连错数据库。加 set -u 后,只要引用未声明变量,Bash 就立刻退出,并打印类似 script.sh: line 5: CONF_DIR: unbound variable 的错误。
必须放在脚本最开头,且不能被条件跳过
set -u 只对它之后的变量引用生效。常见错误是把它塞在 if 分支里、函数内部,或放在注释/空行之后:
- ✅ 正确:第一行或第二行(紧接 shebang),例如
#!/bin/bash下一行就写set -u - ❌ 错误:
if [ "$DEBUG" = "1" ]; then set -u; fi—— 条件不满足时完全不生效 - ❌ 错误:
set -u写在echo "start"后面 —— 前面那行如果用了未定义变量,已经逃逸了检查
变量有值但为空,不算“未定义”,set -u 不管
set -u 只拦截根本没 declare / = 赋过值的变量,不管它是不是空字符串。比如:
set -u NAME="" # ✅ 合法:已定义,只是值为空 echo "$NAME" # 输出空行,不报错 echo "$AGE" # ❌ 报错:AGE 根本没出现过
如果你要防“空值误用”,得配合参数扩展:
- 用
${VAR:?required}在变量为空或未定义时强制报错退出 - 用
${VAR:-default}提供兜底值,避免后续命令崩溃 - 别依赖
set -u检查业务逻辑上的“空”,它只管语法层面的“未声明”
和 set -e、pipefail 搭配才真正可靠
单独 set -u 只防变量名错误,不防命令失败。比如 rm /nonexistent 失败后脚本仍继续执行,可能把后续关键步骤全绕过去。生产脚本建议默认写:
#!/bin/bash set -euo pipefail
其中:
-
set -e:任何命令非零退出,立刻终止 -
set -o pipefail:管道里任意一环失败,整个管道算失败(否则默认只看最后一段) - 三者合体才能覆盖变量、命令、管道三类最常见静默失效场景
注意:set -euo pipefail 会让 if、while、&&/|| 等结构的行为变严格,写条件判断时得显式处理退出码,否则容易意外中断。











