Bash重定向stderr到文件后错误陷阱无法捕获输出的问题
问题分析与修复方案
核心问题1:ERR陷阱未触发
原脚本仅通过set -e开启遇错即退,但默认情况下ERR陷阱不会在函数、子shell中继承触发。当install_zypper_packages函数内的zypper install命令失败时,set -e触发脚本退出,但陷阱未被调用。需添加set -E选项,让ERR陷阱在函数和子shell中生效。
核心问题2:终端提示符与输出同行
最后一行使用echo -n输出后,命令失败导致后续的echo 'OK'未执行,终端光标停留在该行末尾,提示符直接接在后面。需在错误处理函数中先输出换行,确保提示符在新行。
修复后的完整脚本
#!/usr/bin/env bash ############################### # env variables ############################### # 环境变量 - 安装日志文件路径及待安装依赖清单路径 readonly LOGS_DIRECTORY="./logs/cherry-install/" readonly LOGS_FILE="${LOGS_DIRECTORY}$(date +%d-%m-%y_%H-%M-%S).txt" readonly ZYPPER_PACKAGES="./dependencies/zypper_packages.txt" readonly ZYPPER_PATTERNS="./dependencies/zypper_patterns.txt" ############################### # 非安装类函数 ############################### # 创建日志目录 mkdir -p "$LOGS_DIRECTORY" # 重定向stdout和stderr到日志文件,保留fd3用于终端输出 exec 3>&1 1>>"$LOGS_FILE" 2>&1 echo() { >&3 command echo "$@" } # 开启遇错即退,并允许ERR陷阱在函数/子shell中继承生效 set -eE # 错误处理函数:触发时打印提示信息 error_handler(){ # 先输出换行,解决提示符与输出同行问题 echo -e "\n 发生错误!请查看安装日志文件获取详细信息。\n" # 保留原错误码并退出 exit $? } trap 'error_handler' ERR trap "echo -e '\n安装已被手动终止!'; exit" SIGINT # 通用函数:从文件读取依赖名称 read_file(){ packages=() while IFS= read -r line || [[ -n "$line" ]]; do packages+("$line") done < "$1" } ############################### # 安装类函数 ############################### # Zypper仓库刷新及包安装 install_zypper_packages(){ read_file "$ZYPPER_PACKAGES" echo -n "[i] 刷新Zypper仓库: " zypper -n refresh echo '完成' for line in "${packages[@]}"; do clean_line="${line//[^[:alnum:]-]/}" echo -n "[i] 安装 $clean_line: " zypper -n install -t package "$clean_line" echo '完成' done echo "" } install_zypper_packages
关键修复点说明
- 添加
set -E:让ERR陷阱能够在函数、子shell等上下文中触发,确保命令失败时错误处理函数被调用。 - 错误处理函数开头添加换行:解决
echo -n未完成换行导致提示符与输出同行的问题。 - 优化
LOGS_FILE变量定义:使用更规范的变量拼接方式,避免不必要的双引号嵌套。 - 自定义
echo函数改用大括号{}:避免子shell带来的潜在性能问题(原写法用子shell也能工作,但大括号更高效)。 - 错误处理函数中保留原错误码:方便后续脚本或调用者判断执行结果。
内容的提问来源于stack exchange,提问作者Krzysztoff
相关产品推荐
相关产品推荐

