Linux服务器Git自动提交Cron任务为何每小时发送邮件?
问题:Cron任务每小时自动发送邮件(本该仅失败时发送)
需求:服务器上每小时自动提交指定Git仓库的所有变更,仅当任务失败时,通过msmtp发送包含stdout和stderr的邮件。
当前配置:
Cron任务:
59 */1 * * * git-auto_commit.sh 2>&1 | msmtp address@domain.tld
git-auto_commit.sh脚本内容:
#!/usr/bin/env bash git_path="$HOME/git_repos" repo_array=( "repo1" "repo2" "another_repo" ) eval "$(ssh-agent -s)" if [ -e ~/.ssh/my_private_key ] then ssh-add ~/.ssh/my_private_key fi for repo in ${repo_array[@]} do if [ -d $git_path/$repo ] then echo "##############################" echo "Current repos: " $repo cd "$git_path/$repo" if [[ $(git status --porcelain) ]] then git pull git add -A git commit -m "automated commit" git push else echo "No changes found" fi echo "##############################" else echo "The path $git_path/$repo doesn't exist" fi done eval $(ssh-agent -s -k)
任务正常执行输出示例:
Agent pid 16469 Identity added: /home/username/.ssh/my_private_key ############################## Current repos: repo1 No changes found ############################## ############################## Current repos: repo2 No changes found ############################## Agent pid 16469 killed
问题:Cron任务可正常执行,但每小时都会收到邮件,不符合仅失败时发送的要求。
原因分析
当前Cron命令通过2>&1 | msmtp将脚本的**所有输出(包括标准输出stdout和标准错误stderr)**都传递给msmtp。而你的脚本在正常执行时也会产生大量stdout输出,比如ssh-agent启动信息、仓库检查提示、"No changes found"等内容。只要msmtp收到输入,就会发送邮件,完全不关心脚本是否执行失败。
解决方法
方法一:仅在脚本执行失败时发送邮件
修改Cron任务,先捕获脚本输出,再判断脚本退出码(非0表示执行失败),仅失败时发送邮件:
59 */1 * * * output=$(/path/to/git-auto_commit.sh 2>&1); if [ $? -ne 0 ]; then echo "$output" | msmtp address@domain.tld; fi
注意:需要替换
/path/to/git-auto_commit.sh为脚本的实际绝对路径(Cron的环境变量可能不包含脚本所在目录)。
方法二:修改脚本,正常执行时无输出
将脚本中所有非错误相关的输出重定向到/dev/null,仅保留错误提示,并设置正确的退出码:
#!/usr/bin/env bash git_path="$HOME/git_repos" repo_array=( "repo1" "repo2" "another_repo" ) # 启动ssh-agent时不输出信息 eval "$(ssh-agent -s >/dev/null 2>&1)" if [ -e ~/.ssh/my_private_key ] then # 添加密钥时不输出信息 ssh-add ~/.ssh/my_private_key >/dev/null 2>&1 fi exit_code=0 for repo in ${repo_array[@]} do if [ -d $git_path/$repo ] then cd "$git_path/$repo" if [[ $(git status --porcelain) ]] then # 每个Git命令失败时设置退出码为1 git pull || exit_code=1 git add -A || exit_code=1 git commit -m "automated commit" || exit_code=1 git push || exit_code=1 fi else echo "ERROR: The path $git_path/$repo doesn't exist" exit_code=1 fi done # 关闭ssh-agent时不输出信息 eval $(ssh-agent -s -k >/dev/null 2>&1) # 返回最终退出码 exit $exit_code
修改后,Cron命令可保留原格式,但只有脚本出错时才会有输出,触发msmtp发送邮件。
方法三:将正常输出写入日志,仅失败时发送日志内容
如果需要保留正常执行的日志,同时仅失败时发送邮件:
59 */1 * * * /path/to/git-auto_commit.sh >/var/log/git-auto-commit.log 2>&1; if [ $? -ne 0 ]; then cat /var/log/git-auto-commit.log | msmtp address@domain.tld; fi
这样脚本的所有输出都会写入日志文件,只有执行失败时,才会把日志内容作为邮件发送。
内容的提问来源于stack exchange,提问作者maxmoon
相关产品推荐
相关产品推荐

