← 中文资源

简体中文版本

Bash 严格模式与错误陷阱

用 set -euo pipefail 加 ERR 陷阱加固脚本:静默失败变成带行号与命令的响亮退出,显式容忍用注释与 or true 声明。

阅读英文原文

示例说明

裸 bash 脚本的默认行为是错完继续跑:未定义变量展开成空串、管道里第一个命令失败被末尾成功掩盖,最终以零退出码伪装成功毁掉数据。三个开关分别堵住三条路:-e 失败即退、-u 未定义即炸、-o pipefail 管道任一段失败整体失败。ERR 陷阱把失败现场——行号、命令、退出码——在退出前打印出来。

技术要点

  • set -euo pipefail 是脚本的默认开头
  • ERR 陷阱输出行号与命令现场
  • || true 显式声明容忍的点

代码解读

on_error 从 $? 取退出码、BASH_LINENO 取行号、BASH_COMMAND 取失败命令,三条信息定位任何失败点;readonly 的 SCRIPT_DIR 是取脚本所在目录的惯用法(含空格路径安全)。count_lines 里的 || true 演示显式容忍:grep 无匹配返回一属正常,用 or true 明示这不是疏漏。

使用建议

函数内 set -e 有边界情况,关键路径显式判断返回值更稳。source 该脚本时 ERR 陷阱会影响宿主,加作用域判断。shellcheck 静态检查应纳入 CI。

代码示例

#!/usr/bin/env bash
# 严格模式三件套 + 错误陷阱
set -euo pipefail

readonly SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"

on_error() {
  local exit_code=$?
  local line=${BASH_LINENO[0]:-unknown}
  echo "Error: 脚本在第 ${line} 行失败,退出码 ${exit_code}" >&2
  echo "Error: 执行到此处时的命令:${BASH_COMMAND}" >&2
  exit "${exit_code}"
}
trap on_error ERR

# pipefail 演示:管道中段失败不再被吞掉
count_lines() {
  grep -c '^data:' "$1" || true   # 显式容忍:grep 无匹配返回 1
}

main() {
  local input="${SCRIPT_DIR}/events.log"
  local lines
  lines=$(cat "$input" | wc -l) || return 1
  echo "total lines: ${lines}"
  echo "data lines: $(count_lines "$input")"
}

main "$@"