输出与邮件的关系
cron 执行任务时,命令写往标准输出和标准错误的内容不会被丢掉,而是拼成一封邮件投递给 crontab 的所有者,收件人由 MAILTO 变量决定。问题在于:多数服务器根本没装邮件服务,这封邮件要么堆在本地邮件池里没人看,要么直接投递失败,于是「任务报错」这件事就静默消失了。生产上的通行做法是关掉邮件通道、把输出显式重定向到带日期的日志文件,再由监控按日志与退出码告警。
基本信息
| 用途 | 控制定时任务的输出与错误去向 |
|---|---|
| 默认行为 | 标准输出与标准错误合并后以邮件投递给 crontab 所有者 |
| 所属 | vixie-cron / cronie 的 crontab(5) 规范 |
| 推荐做法 | MAILTO 置空关闭邮件,任务末尾统一重定向到日志文件 |
典型使用场景
- 任务静默失败:没有邮件服务,报错无人可见,必须改成写日志加告警
- 日志集中管理:把定时任务输出统一落到 /var/log 下,交给采集器与轮转统一处理
- 保留执行证据:备份、清理这类有副作用的任务,输出留痕便于事后核对
- 减少噪音:只为真正失败的任务发通知,避免每分钟一封「执行成功」的邮件
- 排查环境差异:任务在命令行能跑、在 cron 里失败时,把环境变量与错误一起写下来对比
推荐写法
推荐写法
MAILTO="" # 关闭邮件投递(注意是所有任务一起生效)
SHELL=/bin/bash
PATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin
30 2 * * * /opt/app/backup.sh >> /var/log/app/backup.log 2>&1
30 3 * * * /opt/app/sync.sh >> /var/log/app/sync.log 2>&1重定向顺序与退出码
重定向顺序与退出码
# 正确:输出和错误都进文件
/opt/app/task.sh >> /var/log/app/task.log 2>&1
# 错误:顺序颠倒,stderr 仍指向原来的去处
/opt/app/task.sh 2>&1 >> /var/log/app/task.log
# 只关心成败、不要输出:丢弃内容但保留退出码
/opt/app/task.sh > /dev/null 2>&1 || logger -t cron-task 'task failed'
# 查看是否有未读的 cron 邮件(装了邮件服务时)
ls -l /var/spool/mail/$(id -un) 2>/dev/null; mail 2>/dev/null | headMAILTO 取值对照
| 取值 | 效果 | 适用 |
|---|---|---|
| MAILTO=""(空值) | 不发送任何邮件 | 已有监控与日志系统,服务器没装 MTA |
| MAILTO=ops@example.com | 发到指定地址 | 确实有 MTA,且希望靠邮件收告警 |
| MAILTO=root | 投递给本地 root | 本机有邮箱且在登录时查看 |
| 不设置该变量 | 默认发给 crontab 所有者 | 容易被忽略的默认行为 |
重定向顺序直接决定错误信息去哪:先写 >> 文件再写 2>&1,标准错误才会跟随到文件;写成 2>&1 >> 文件 时,错误仍会流向 cron 的邮件通道。
更稳的做法是在脚本内部完成日志与通知(配合 set -euo pipefail 与 logger 写系统日志),crontab 里只负责调用脚本。这样脚本在命令行手工执行时的行为与定时执行一致,便于复现问题。