shell函数可通过exec重定向stdout和stderr至日志文件,并结合trap捕获err信号记录行号与命令,实现完整错误日志;需注意子shell不继承重定向、必须合并stderr、避免仅用set -e。

Shell函数本身不自带“捕获错误日志”的机制,但可以通过组合重定向、set -e、trap和文件描述符控制,把函数内所有命令的标准输出和标准错误(包括报错信息)完整记录到指定日志文件。关键不是“捕获错误”,而是让错误流不丢失、不混在终端里,统一导向日志。
用 exec 在函数开头统一重定向
最直接可靠的方式:在函数体第一行用 exec 重定向整个函数作用域的 stdout 和 stderr。
-
exec > "$log_file" 2>&1把后续所有输出(含错误)写入日志,覆盖原内容 -
exec >> "$log_file" 2>&1追加写入,适合多次调用同一函数 - 注意:该重定向只对当前 shell 环境生效,若函数内启用了子 shell(如管道、
$(...)),需额外处理
用 trap 捕获异常并记录错误上下文
仅靠重定向能记录错误输出,但无法知道哪一行出错、什么命令失败。配合 trap 可增强可追溯性:
- 在函数开头设置:
trap 'echo "[ERROR] $(date): line $LINENO, cmd: $BASH_COMMAND" >> "$log_file"' ERR -
$LINENO记录出错行号,$BASH_COMMAND记录实际执行的命令 - 该 trap 会在任意命令非零退出时触发,自动追加结构化错误标记
封装带日志能力的函数模板
把重定向 + trap + 时间戳封装成可复用模式,避免每次重复写:
- 定义通用日志函数:
log_func() { local func_name="$1" log_file="$2"; shift 2; exec >>"$log_file" 2>&1; trap "echo \"[\$(date +'%H:%M:%S')] [ERR in $func_name] line \$LINENO: \$BASH_COMMAND\" >>\"$log_file\"" ERR; echo "[$(date +'%H:%M:%S')] [$func_name] START" >>"$log_file"; "$func_name" "$@"; echo "[$(date +'%H:%M:%S')] [$func_name] END" >>"$log_file"; } - 被调用函数保持原逻辑,无需修改;调用时传入函数名和日志路径即可
- 这样既保留函数原有行为,又自动获得带时间戳、行号、命令体的完整日志
避免常见陷阱
几个容易忽略但影响日志完整性的点:
- 不要只重定向 stdout(
>),必须显式合并 stderr(2>&1),否则错误信息会漏掉 - 函数内若有
subshell(比如(cmd)或cmd | grep),其内部重定向不继承父函数的exec,需在子 shell 内单独重定向 -
set -e虽可让函数遇错退出,但它不生成日志,只是终止执行;必须配合重定向或 trap 才能留下痕迹 - 日志文件路径建议用绝对路径,避免因脚本执行位置不同导致写入失败











