定时任务又没跑?cron 排错五步
定时任务又没跑?cron 排错五步
rsync 备份脚本,手动跑得好好的;塞进 crontab 每天 2:30 跑,第二天一看,备份目录是空的。脚本没动过,cron 也没见报错——或者报错了,你根本没看见。
核心一句话先摆出来:cron 的运行环境和你的登录 shell 是两码事。手动能跑、定时不跑,九成是环境问题,不是脚本问题。
第一步:确认 cron 真的在干活
先看服务活没活着:
systemctl status cron # Debian/Ubuntu 叫 cron
systemctl status crond # RHEL/CentOS 叫 crond
再看任务有没有被加载:crontab -l 能看到才算数。改完 crontab 不用重启,cron 每分钟自己重读,但语法写错了它可不会提醒你。
最后看它到底触发过没有:
grep CRON /var/log/syslog # Debian/Ubuntu
grep CRON /var/log/cron # RHEL/CentOS
# 或者
journalctl -u cron --since "1 hour ago"
日志里出现 (root) CMD (/home/deploy/backup.sh),说明触发了,问题在执行环节;连这行都没有,问题在任务本身没被调度起来。
第二步:环境变量——头号嫌疑人
cron 给任务的环境极简:PATH 通常只有 /usr/bin:/bin,不加载 ~/.bashrc,工作目录是你的家目录。
最经典的死法:脚本里写了 rsync、docker、python3,手动跑时 PATH 里有 /usr/local/bin,cron 里没有 → command not found,任务静默失败。
两种治法,选一种坚持到底:
- 脚本里所有外部命令写绝对路径(
which rsync查出来写死); - 或者在 crontab 文件开头声明环境:
SHELL=/bin/bash
PATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin
30 2 * * * /home/deploy/backup.sh
顺带:脚本里凡是依赖当前目录的,开头加一行 cd /确定的/目录 || exit 1。
第三步:输出去哪了——没日志等于没排错
cron 默认把任务的输出发邮件给本机用户。服务器上没配 MTA,这些输出直接石沉大海,你看到的只有"没跑"。
铁律:每条定时任务都必须有自己的日志文件:
30 2 * * * /home/deploy/backup.sh >> /var/log/backup.log 2>&1
2>&1 不能省——报错信息走的是 stderr,不加它,恰恰最关键的错误信息丢了。
第四步:% 转义——crontab 专属的坑
crontab 语法里 % 是特殊字符,会被转成换行。于是:
# 错:% 被吃掉,date 命令被拦腰截断
0 2 * * * /bin/date +%F >> /tmp/date.log
# 对:反斜杠转义
0 2 * * * /bin/date +\%F >> /tmp/date.log
这个坑只存在于 crontab 行内——脚本文件里写 date +%F 完全没问题。坑的是把带 % 的命令直接写在 crontab 里的人。
第五步:权限、用户、时区三件套
- 权限:脚本必须有执行权限(
chmod +x),cron 不会帮你补。 - 用户:
crontab -e是当前用户的任务;/etc/crontab和/etc/cron.d/是系统任务,必须写用户名那一列(30 2 * * * root /home/deploy/backup.sh),漏了用户整行不生效。 - 时区:
date看一眼。很多云服务器默认 UTC,你设的"2:30"可能是 UTC 的 2:30,也就是北京时间 10:30。用timedatectl确认,时区不对先对时区。
三个真实踩坑
1. 脚本里写了相对路径。 cron 的 HOME 是对的,但"当前工作目录"未必是你想的那个。凡是路径,写绝对的。
2. 任务加到了 root 的 crontab,脚本却在普通用户家目录下,root 读不了。 跨用户调用,先想权限。
3. 用 */5 * * * * 跑一个要 10 分钟的任务。 cron 不管上一次跑完没,到点就起新的,两个实例互相踩。长任务加文件锁(flock -n /tmp/backup.lock),或者换 systemd timer,它有防重叠语义。
什么时候别用 cron
- 需要失败重试、依赖编排:用 systemd timer + service(Restart= 定向拉起);
- 秒级调度:cron 最小粒度 1 分钟;
- 机器会休眠关机:错过的任务 cron 不会补跑。
收尾一句话:cron 只管"到点叫醒",不管"醒来之后世界对不对"。排错按顺序来:服务活着 → 任务被加载 → 环境变量 → 输出日志 → 权限时区。五步走完,定时任务再闹脾气,你至少知道去哪儿找它。
- 点赞
- 收藏
- 关注作者
评论(0)