极简工具箱

免费在线工具 · 本地计算 · 无需上传

crontab 定时任务不执行的六个原因

手动跑脚本一切正常,加到 crontab 里就毫无反应,日志也没有。多数情况下不是 cron 坏了,而是「它跑在了一个几乎空的环境里」。

广告位(百度联盟)

一、先确认它到底跑没跑

crontab -l                     # 当前用户的定时任务
grep CRON /var/log/syslog      # Debian/Ubuntu
grep CRON /var/log/cron        # CentOS/RHEL
systemctl status cron          # 服务是否在运行

日志里出现 (root) CMD (xxx) 说明触发了,问题在脚本内部;完全没有记录,说明 cron 服务没跑或时间表达式不匹配。

二、六个经典原因

1. 环境变量缺失

cron 不加载 .bashrc、.profile,PATH 通常只有 /usr/bin:/bin。于是 python3、node、docker 全成了「command not found」。

解决:在 crontab 顶部显式声明,或用绝对路径。

PATH=/usr/local/bin:/usr/bin:/bin
LANG=zh_CN.UTF-8
SHELL=/bin/bash

2. 相对路径

cron 的工作目录是用户家目录,不是脚本所在目录。脚本里写 ./data.json 会找不到。要么在脚本里 cd $(dirname $0),要么在 crontab 里先 cd。

3. % 需要转义

crontab 里 % 是特殊字符(表示换行),date +%F 必须写成 date +\%F。这也是「命令里带日期就失效」的原因。

4. 脚本没有执行权限

./backup.sh 需要 chmod +x,或者直接用 bash /path/backup.sh 调用(更稳,不依赖 shebang 和权限)。

5. 时区不对

服务器是 UTC,你按北京时间写了 0 2 * * *,实际是北京时间 10 点执行。检查 timedatectl,或在 crontab 顶部加 CRON_TZ=Asia/Shanghai(部分实现支持),最稳的是把服务器时区设为 Asia/Shanghai。

6. 上一次还没跑完

任务耗时超过间隔,多个实例叠在一起抢同一份文件。用 flock 加锁:

*/5 * * * * flock -n /tmp/backup.lock /bin/bash /opt/backup.sh >> /var/log/backup.log 2>&1

-n 表示拿不到锁就跳过本次,不排队。

三、一定要重定向输出

cron 会把脚本的 stdout/stderr 通过邮件发给用户,服务器没配邮件就全部丢弃。所以出错时什么都看不到:

0 2 * * * /bin/bash /opt/backup.sh >> /var/log/backup.log 2>&1

>> 追加、2>&1 把错误也写进去。长期运行要配 logrotate,否则日志会撑满磁盘。

四、时间表达式回顾

0 2 * * *        每天 2:00
*/10 * * * *     每 10 分钟
0 9-18 * * 1-5   工作日 9–18 点整点
0 3 1 * *        每月 1 日 3:00

五个字段顺序是「分 时 日 月 周」。写完用 Cron 解析工具 看中文释义和未来 5 次执行时间,比脑推可靠。推算出来的时间点还可以用 时间戳转换 核对时区。

五、更现代的选择

crontab 适合「简单、单机、不需要补跑」的场景,够用但排错信息少。

六、排查清单

  1. cron 服务在跑吗?
  2. 日志里有 CMD 记录吗?
  3. 用 bash -x 手动模拟同样的环境跑一遍(env -i /bin/bash script.sh)。
  4. PATH、时区、工作目录对不对?
  5. 脚本权限、% 转义、输出重定向有没有问题?
  6. 有没有并发重叠?

小结

cron 的环境几乎为空:显式设 PATH 和时区、用绝对路径、% 转义、记得 >> log 2>&1、用 flock 防重叠。先看日志确认有没有触发,再查脚本内部。

本文相关工具(本地计算,无需上传)

更多使用教程