如何将Bash脚本输出重定向至日志,仅把错误传给邮件脚本?
问题解决与代码修正
核心问题分析
- 重定向逻辑错误:原代码中
&>> "$OUT_FILE" 2> ERROR_OUTPUT无法同时将所有输出写入日志并单独捕获错误——&>>已经将stdout和stderr合并写入日志,后续的2>不会生效。 - 错误内容传递方式错误:直接使用
$ERROR_OUTPUT传递的是变量名而非实际错误内容,且未加引号导致内容被shell拆分。 - mail命令参数错误:多数环境下
mail的主题参数是-s而非-a,-a通常用于添加附件或自定义头信息。 - eval存在安全风险:拼接命令字符串再eval执行,若变量包含特殊字符会引发意外执行。
修正后的run_job.sh
# 定义临时错误文件,用进程ID避免冲突 ERROR_FILE="/tmp/job_error_$$.log" { printf "\n----- PROCESS STARTED %s -----\n" "$(date +%Y-%m-%d\ %H:%M:%S)" # 替换eval为直接执行,避免安全风险 printf "Executing command: cd %s && %s\n\n" "$JOB_FOLDER_PATH" "$EXEC_COMMAND" cd "$JOB_FOLDER_PATH" && "$EXEC_COMMAND" COMMAND_EXIT_CODE=$? printf "\n----- PROCESS ENDED %s -----\n\n" "$(date +%Y-%m-%d\ %H:%M:%S)" } > >(tee -a "$OUT_FILE") 2> >(tee -a "$OUT_FILE" > "$ERROR_FILE") # 命令失败时发送邮件 if [ "$COMMAND_EXIT_CODE" -ne 0 ]; then # 读取错误文件内容作为邮件正文,双引号保留格式 bash ./send_email.sh "Job Failed" "$(cat "$ERROR_FILE")" fi # 清理临时文件 rm -f "$ERROR_FILE"
修正后的send_email.sh
MAIL_SUBJECT="$1" MAIL_BODY="$2" # 修正mail命令参数:-s指定主题,-a添加From头 echo "$MAIL_BODY" | \ mail -s "$MAIL_SUBJECT" \ -a "From: Kaizen Service <service@kaizen.co.uk>" \ "$(grep -o '^[^#]*' "$MAILING_LIST_FILE" | tr '\n' ',')"
关键改进说明
- 重定向逻辑:通过
tee实现双输出——stdout和stderr都写入日志文件,同时stderr单独写入临时错误文件。 - 安全执行命令:去掉
eval,直接执行cd "$JOB_FOLDER_PATH" && "$EXEC_COMMAND",避免变量特殊字符引发的安全问题。 - 正确传递内容:用
$(cat "$ERROR_FILE")读取错误内容,并用双引号包裹,保证内容格式和完整性。 - 兼容mail命令:改用
-s指定主题,符合多数mail/mailx工具的参数规范。
内容的提问来源于stack exchange,提问作者Tamir Hen
相关产品推荐
相关产品推荐

