set -e 仅对单独命令或管道末尾命令生效,不捕获管道中间失败、if/&&/|| 中非末尾命令;需显式判断 $? 或用 ${var:?} 校验变量;循环应避免 for f in $(ls),改用 find -print0 | while read -r -d '';set -x 需配对 set +x 防止日志泄露。

用 set -e 之前先搞清它到底在什么情况下不退出
很多人加了 set -e 就以为脚本“出错自动停”,结果发现 grep 没匹配到却没退出,|| 后面的命令照常执行——因为 set -e 对管道、if 判断、&&/|| 链里的非最后一个命令默认不生效。
真正可靠的写法是:把关键检查单独成行,或显式判断返回值:
grep "pattern" file.txt if [ $? -ne 0 ]; then exit 1; fi
常见踩坑点:
-
set -e不捕获command || echo "fallback"中command的失败 - 管道中只有最后一个命令失败才会触发退出:
cat file.txt | grep "x" | sort,中间grep失败不会退出 - 函数内部的
set -e不会继承到调用者作用域
变量未定义就引用?${var:?} 比 test -z "$var" 更直接
空值或未定义变量导致脚本逻辑错乱,但每次手动 if [ -z "$var" ] 太啰嗦。直接用参数扩展强制校验更省事,也更早暴露问题。
实操建议:
本书以培养高级网站建设与管理人才为目标,内容循序渐进,由浅入深,通过大量的实例系统全面地介绍了Linux+PHP+MySQL环境下的网络后台开发技术。本书详尽分析了近30个典型案例。包括计数器、网站流量统计、留言板、论坛系统、聊天室、投票与调查、用户管理、新闻发布系统、广告轮播、购物系统等等,力求让读者通过对案例的学习,轻松掌握PHP和MySQL的编程精要,迅速掌握网络后台开发技巧。 本书适
- 必须存在的变量:用
${var:? "var is required"},未定义或为空时立即报错退出 - 允许为空但不能未定义:用
${var?}(注意没冒号),只对未定义报错 - 别混用
${var:-default}和${var:?}——前者是兜底,后者是断言,目的完全不同 - 在
source配置文件里大量用${var:?},比运行时才发现变量缺失强得多
循环处理文件名含空格?别用 for f in `ls`
for f in `ls` 或 for f in $(find ...) 在遇到带空格、换行、* 等特殊字符的文件名时必然崩,这不是边缘情况,而是日常。
可靠方案只有两个:
- 用
while read -r配合find -print0:find . -name "*.log" -print0 | while IFS= read -r -d '' file; do echo "Processing: $file" done
- 用数组 +
glob(bash 4.4+):files=( *.log ) for f in "${files[@]}"; do [ -e "$f" ] || continue # 防空匹配 echo "Processing: $f" done - 永远别在循环变量里直接插
$f,一律用"$f"包裹
调试时想看每条命令实际执行啥?set -x 要和 set +x 配对关
set -x 打印执行前的命令(带变量展开),非常有用,但开太久会导致日志爆炸,尤其在循环或递归调用里。
实用习惯:
- 只在怀疑段落前后加:
set -x some_tricky_command arg1 "$var" set +x
-
set -x输出里的+是提示符,不是命令一部分;看到+ cd /tmp说明cd真被执行了 - 如果脚本被其他脚本
source,set -x会影响父脚本,所以优先用局部子 shell:(set -x; some_command)
- 别依赖
set -x查变量值——它只显示展开后的命令,不显示变量原始内容
最常被忽略的是:set -x 开启后,所有后续子 shell、函数调用都会继承,除非显式关闭。漏关 set +x 的脚本上线后可能把敏感路径、参数全打到日志里。










