crontab 写了任务,时间到了却什么都没发生——这是运维里很常见的问题。原因通常不是 cron 服务坏了,而是环境、路径、权限或语法出了偏差。下面按从外到内的顺序,一步步排查,基本能覆盖 90% 的情况。
先确认 cron 服务本身在运行
如果 cron 守护进程没启动,所有任务都不会执行。不同发行版的服务名不一样:
# Debian/Ubuntu
systemctl status cron
# CentOS/RHEL
systemctl status crond
如果状态不是 active (running),先启动并设为开机自启:
sudo systemctl start cron # 或 crond
sudo systemctl enable cron
另外,有些容器环境(如 Alpine)默认不装 cron,需要手动安装并启动。
检查 crontab 语法和用户
语法错误会导致整行被忽略,而且 cron 不会报错。常见坑:
- 五个时间字段顺序错:分 时 日 月 周
- 命令后面没加
>> /var/log/xxx.log 2>&1,输出被丢弃,看起来像没执行 - 用
%时没转义,cron 会把%当成换行符
用 crontab -l 查看当前用户的任务;如果是系统级任务,检查 /etc/crontab 和 /etc/cron.d/ 下的文件。注意系统级 crontab 多一个用户字段,别和用户级搞混。
环境变量和路径是最大元凶
cron 执行时的环境非常干净,PATH 通常只有 /usr/bin:/bin,你 shell 里能跑的命令它可能找不到。比如 node、python3、docker 装在 /usr/local/bin,直接写命令名就会失败。
解决办法:命令用绝对路径,或者在 crontab 顶部显式设置环境变量:
PATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin
SHELL=/bin/bash
0 3 * * * /usr/bin/python3 /home/app/backup.py >> /var/log/backup.log 2>&1
另外,cron 不读取 ~/.bashrc 和 ~/.profile,所以你在里面设的变量它一概不知。需要的话,在脚本开头手动 source 或直接写死。
看日志,别靠猜
如果任务确实触发了但命令失败,日志会告诉你原因。不同系统日志位置不同:
# Debian/Ubuntu
grep CRON /var/log/syslog
# CentOS/RHEL
grep CRON /var/log/cron
# 使用 journalctl
journalctl -u cron --since "10 min ago"
日志里会显示 cron 是否执行了该行,以及命令的退出状态。如果连执行记录都没有,说明时间表达式没匹配上,或者任务被 /etc/cron.allow、/etc/cron.deny 限制。
权限与特殊场景
普通用户只能管理自己的 crontab;要用 root 权限执行,得写进 root 的 crontab 或系统级目录。脚本本身要有可执行权限(如果直接执行脚本),或者用解释器调用。另外,服务器时区不对也会导致任务在“错误的时间”执行,用 timedatectl 确认时区。
最后,如果你在 Docker 容器里跑 cron,要确保容器前台进程不退出,并且 cron 服务已启动——很多镜像默认不带。

