You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.17 00:31:39