crontab -l确认 crontab 条目确实存在、时间表达式没写错。
约 1570 字大约 5 分钟
2026-05-14
“定时任务没跑”——但先要分清是根本没触发,还是触发了却失败。后者远比前者常见,而且因为 cron 在你看不见的地方跑、又常常没配日志,可能默默失败很久没人发现。这篇按这条主线排查,相关概念见 systemd timer。
先分清“没触发”还是“触发了失败”,再针对性查时间表达式、cron 服务、以及 cron 环境与交互 Shell 的差异。
crontab -l确认 crontab 条目确实存在、时间表达式没写错。
systemctl status croncron 服务本身挂了,所有任务都不会跑。
journalctl -u cron --since todaycron 触发任务时会留日志,看它到底有没有动。
grep CRON /var/log/syslog有些系统 cron 日志在 syslog 里。
这是整个排查的分岔口:
怎么区分?看 cron 自己的触发日志:
journalctl -u cron --since today # systemd 系统
grep CRON /var/log/syslog # 部分系统在 syslog日志里有那条任务的触发记录 → 触发了,问题在脚本(往下看“触发了失败”)。完全没有记录 → 没触发(往下看“根本没触发”)。
crontab -l # 任务条目还在吗?是不是编辑后没保存?
systemctl status cron # cron 服务本身在运行吗?挂了所有任务都不跑常见原因:
crontab 五个字段(分 时 日 月 周)很容易写错,对照确认systemctl status cron(有些发行版叫 crond)crontab -e如果 cron 触发了、脚本却没成功,最常见的根因是:cron 的运行环境和你的登录终端完全不同。
cron 的环境极简:PATH 只有很短的几个目录、不加载 ~/.bashrc、当前目录是家目录。所以——
手动跑好好的脚本,放进 cron 就
command not found或“找不到文件”。
这跟 Shell 是什么 里讲的非交互 Shell 是同一回事。对策:
/usr/bin/python3 而不是 python3),或在脚本开头显式设 PATH.bashrc 继承cron 任务在你看不见的地方跑。如果它没把输出写到任何地方,失败了你根本无从知道。所以排查的同时,也要把日志补上:
# crontab 里给任务加上输出重定向
0 3 * * * /opt/scripts/backup.sh >> /var/log/backup.log 2>&12>&1 把错误也一起记下来——你尤其需要错误日志。补好日志后,下次失败就有据可查(更系统的做法见 脚本日志与错误处理)。
不管哪种情况,一个有效的手段是手动跑一遍脚本,但模拟 cron 的环境:
# 直接手动跑:能跑通说明脚本逻辑没问题,问题在 cron 触发或环境
/opt/scripts/backup.sh
# 用尽量干净的环境跑:复现 cron 的“极简环境”
env -i /bin/sh -c '/opt/scripts/backup.sh'手动跑通、env -i 跑挂 → 基本锁定是环境问题。
没有日志的定时任务,本身就是个隐患
最坑的定时任务故障:一个备份脚本默默失败了三个月,没人发现,直到真的需要那份备份。所以排查的同时务必把这件事做了——给每个定时任务配上日志(输出重定向或交给 journald),确认失败时退出码非 0、且日志里看得出原因。定时任务“能跑”不够,要“跑挂了有人知道”。另外别忘了日志文件本身也要纳入 logrotate,否则它自己会把磁盘写满。
| 误区 | 更稳妥的做法 |
|---|---|
| 不分“没触发”和“触发了失败”就乱查 | 先看 cron 触发日志,有记录查脚本、没记录查触发 |
| 假设 cron 环境和登录终端一样 | cron 环境极简,脚本里命令和文件都用绝对路径 |
| 定时任务不配任何日志 | 给任务加 >> log 2>&1,失败才查得到 |
| 只在自己终端跑通就以为没问题 | 用 env -i 模拟 cron 的干净环境复现 |
版权归属:Shuo Liu