| 核心结论 | 说明 |
|---|---|
set -e 不是万能错误处理 | 它有很多例外场景,不能替代显式判断 |
set -u 处理的是未定义变量,不是空变量 | 变量已定义但值为空不会报错 |
管道必须配合 set -o pipefail | 否则管道返回值默认取最后一个命令 |
set -x 适合调试,不适合长期打开 | 可能打印敏感变量、Token、密码 |
常见组合是 set -Eeuo pipefail | 但要理解副作用,不建议无脑复制 |
1.简介
set 是 Bash 内建命令,用于修改当前 Shell 的运行参数。
脚本中常见写法:
| |
或:
| |
这些参数可以提升脚本失败时的可见性,但也会改变脚本控制流。生产脚本中建议使用,但必须理解它们的边界。
2.说明
2.1 常用参数总览
| 参数 | 长写法 | 作用 |
|---|---|---|
set -e | set -o errexit | 命令返回非 0 时退出脚本 |
set -u | set -o nounset | 使用未定义变量时报错 |
set -x | set -o xtrace | 执行命令前打印展开后的命令 |
set -o pipefail | - | 管道中任一命令失败,则整个管道失败 |
set -E | set -o errtrace | 让 ERR trap 继承到函数、子 Shell、命令替换 |
查看当前 Shell 参数:
| |
临时关闭某个参数:
| |
2.2 set -u:未定义变量直接报错
set -u 只针对未定义变量,不针对空字符串。
| |
输出:
| |
空变量不会报错:
| |
处理可选变量时,建议使用默认值写法:
| |
区别:
| 写法 | 含义 |
|---|---|
${var:-default} | 变量未定义或为空时使用默认值 |
${var-default} | 变量未定义时使用默认值,变量为空则仍为空 |
${var:?message} | 变量未定义或为空时报错并退出 |
必填参数示例:
| |
2.3 set -x:打印执行过程
set -x 会在命令执行前打印展开后的命令,常用于排查脚本执行路径。
| |
输出类似:
| |
可以修改 PS4 增加行号:
| |
需要注意:set -x 会打印变量展开后的值,不适合在含有密码、Token、AK/SK 的脚本中长期打开。
2.4 set -e:命令失败立即退出
默认情况下,Bash 中某条命令失败后,脚本会继续执行。
| |
开启 set -e 后:
| |
false 返回非 0,脚本退出。
手动处理错误:
| |
允许某条命令失败:
| |
或临时关闭:
| |
set -e 只能兜底,不能替代关键步骤的显式错误处理。关键命令建议保留 if 或 || { ... }。2.5 set -e 的常见例外
set -e 有很多不会退出的场景,最容易误判。
2.5.1 if / while 条件判断
| |
grep 未匹配时返回 1,但脚本不会退出,因为它处于 if 条件判断位置。
2.5.2 && / || 命令链
| |
false 不会导致退出,因为它位于 && 命令链中。
2.5.3 取反 !
| |
这种写法不会退出。
2.5.4 管道默认只看最后一个命令
| |
默认情况下,管道整体返回值取最后一个命令 true,所以脚本继续执行。
2.6 set -o pipefail:管道中任一命令失败则失败
开启 pipefail 后:
| |
管道中 false 失败,整个管道返回失败,脚本退出。
常见场景:
| |
如果不启用 pipefail,curl 失败但 bash 可能仍返回 0,脚本会误判成功。
更稳妥的写法:
| |
2.7 set -E 与 trap ERR
trap ERR 可以在命令失败时统一处理错误。
| |
如果没有 set -E,ERR trap 在函数、子 Shell、命令替换中的继承行为会受限。
常见模板:
| |
注意:$BASH_COMMAND 可能包含敏感参数,生产日志中需要谨慎打印。
2.8 推荐模板
普通脚本:
| |
需要统一错误日志:
| |
调试脚本:
| |
不建议长期使用 set -x 跑生产脚本,尤其脚本中包含:
- 数据库密码;
- API Token;
- SSH 私钥路径和参数;
- 云厂商 AK/SK。
2.9 常见坑
| 问题 | 原因 | 建议 |
|---|---|---|
set -u 后可选变量报错 | 变量未定义 | 使用 ${var:-default} |
set -e 没有退出 | 命令在 if/while/&&/` | |
| 管道前半段失败但脚本继续 | 未启用 pipefail | 使用 set -o pipefail |
| 日志泄露密钥 | 开启 set -x | 敏感逻辑前 set +x |
| `command | true` 掩盖真实错误 |
3.总结
set -u处理未定义变量,不处理空变量;set -e可以让脚本在错误时尽快失败,但存在很多例外;- 管道场景必须配合
set -o pipefail,否则默认只看最后一个命令; set -x适合调试,但可能泄露敏感信息;- 常见模板是
set -Eeuo pipefail,但关键命令仍建议显式错误处理。