1. Shell 脚本的健壮性中 set -euo pipefail 与错误处理如何配合?
set -euo pipefail 各选项分别解决什么问题?Shell 脚本的健壮错误处理还应该包括哪些实践?
- set -e(errexit)、-u(nounset)、-o pipefail 的语义与副作用
- 常见坑:命令替换中的失败、if 条件中的失败命令、管道失败
- 配套实践:set -x 调试、trap ERR/EXIT 清理、错误消息输出
set -euo pipefail 是 Shell 脚本健壮性的三件套:set -e 让脚本在任何命令返回非零时立即退出(避免"失败后继续跑"造成连锁错误);set -u 把使用未定义变量当作错误退出(捕获拼写错误与未初始化变量);set -o pipefail 让管道返回"最后一个非零命令"的退出码(默认管道只返回最后一条命令的退出码,中间命令失败会被掩盖)。三者配合后,脚本默认"失败即停、未定义即报、管道不漏错"。注意 set -e 的边界:if/while 条件、&&/|| 左侧、命令替换(取决于版本与上下文)中的失败不会被触发,需要显式处理;临时放行用 cmd || true 或 set +e 局部关闭。
健壮性配套实践:用 set -x 调试跟踪执行;trap '...' ERR 在错误时打印脚本名/行号(结合 $LINENO、$BASH_SOURCE)便于定位;trap cleanup EXIT 在退出时清理临时文件与恢复环境;关键命令加显式检查(if ! cmd; then echo "fail" >&2; exit 1; fi);输出统一走 stderr(>&2)避免污染 stdout 管道;使用 local 限定函数变量、引号包裹所有变量("$var")防分词与通配符扩展;对外部命令返回值(如 curl、rsync)显式校验;脚本开头声明 #!/usr/bin/env bash 与执行前 shellcheck 静态检查。错误处理的目标是"可读、可定位、可重试"。
本题考察 Shell 脚本的健壮性工程。回答要点:三个 set 选项的准确语义与边界(尤其 set -e 的豁免场景与 pipefail 对中间命令失败的捕获)、trap/set -x/引号/local 等配套实践,体现对"脚本事故预防"的系统性理解。
#!/usr/bin/env bash
set -euo pipefail
trap 'echo "ERR at line $LINENO" >&2' ERR
trap cleanup EXIT
cleanup() { rm -f "$TMPFILE"; }
readonly TMPFILE=$(mktemp)
if ! curl -fsS -o "$TMPFILE" "$URL"; then
echo "download failed" >&2
exit 1
fi