crontab 定时任务不执行的六个原因
先说在前面
「脚本手动跑得好好的,放进 crontab 就不动」几乎是每个运维都遇到过的事。crontab 和交互式 shell 的差别不在语法,而在运行环境:它不读你的登录配置、没有终端、工作目录也不是你以为的那个。下面六个原因按出现频率排,每条都给一条能立刻验证的命令。1. PATH 和环境变量几乎全是空的
cron 只给一个极简环境,通常是 PATH=/usr/bin:/bin,不会加载 ~/.bashrc、/etc/profile,也没有你在 shell 里 export 的那些变量。于是 python3、node、docker 或 conda 里的命令全部「command not found」,而 crontab 默认又不把错误显示给你。
* * * * * env > /tmp/cron-env.txt 2>&1
cat /tmp/cron-env.txt
修法有三:命令一律写绝对路径(/usr/bin/python3);在 crontab 顶部显式写 PATH=/usr/local/bin:/usr/bin:/bin;或者让脚本自己 source 需要的配置。最稳的是第一种。
2. 相对路径和工作目录不对
cron 执行时的当前目录是用户家目录(或 /,取决于实现),不是脚本所在目录。脚本里写 ./config.yaml、open('data/log.txt') 就会找不到文件,或者悄悄写到了别的地方。
*/5 * * * * cd /opt/app && /usr/bin/python3 /opt/app/backup.py >> /var/log/backup.log 2>&1
顺便说一句:脚本里用 Path(__file__).parent 而不是 os.getcwd() 定位资3. 命令里的 % 没转义
这是最容易莫名其妙的一条:crontab 中未转义的 % 会被解释成换行,后面的内容当作标准输入传给命令。所以带日期的命令经常只执行了半截。
0 2 * * * /usr/bin/mysqldump db > /backup/db_$(date +%Y%m%d).sql
0 2 * * * /usr/bin/mysqldump db > /backup/db_$(date +\%Y\%m\%d).sql
更省心的做法是把整段逻辑写进 shell 脚本,crontab 里只留一行脚本路径,这样 crontab 的语法规则就不会干扰脚本内容。
4. 输出被吞掉,失败也没人知道
cron 没有终端,标准输出和错误要么丢掉、要么尝试发给本地邮件(大多数机器上根本没配 MTA)。所以「没执行」和「执行了但报错」看起来一模一样。
MAILTO=""
0 3 * * * /opt/app/job.sh >> /var/log/job.log 2>&1
0 3 * * * /opt/app/job.sh >> /var/log/job.log 2>> /var/log/job.err
调试期还可以直接看系统日志确认「调度到底有没有触发」:grep CRON /var/log/syslog(Debian/Ubuntu)或 grep CROND /var/log/cron(RHEL 系)。日志里有 CRON 行就说明调度正常,问题在脚本内部;连行都没有,才是表达式5. 时区改了,cron 还按老时间跑
改系统时区后如果没重启 cron 守护进程,它仍按启动时读到的时区调度,表现是「任务晚八小时执行」。容器里更常见:镜像默认 UTC,业务按北京时间写表达式。
timedatectl
systemctl restart cron
CRON_TZ=Asia/Shanghai
0 9 * * * /opt/app/daily.sh
另外注意「每月 1 日 02:30」这类任务在夏令时切换时可能执行两次或跳过一次,能避开就避开。
6. 文件本身的小毛病
几类低级但高频的问题:脚本没有执行位(chmod +x)、从 Windows 拷过来带 CRLF(file job.sh 能看到,dos2unix 修)、crontab 文件最后一行没有换行符(最后一条任务不会被读取)、shebang 写错或用了不存在的解释器路径。还有一条容易忽略:/etc/cron.d/ 下的文件要求属主是 root 且权限不能组/其他可写,否则 cron 会直接忽略并在日志里留一行 WRONG FILE OWNER 或 BAD FILE MODE。
小结:一条最短的排查顺序
先 grep CRON /var/log/syslog 确认调度有没有触发 → 用 env > /tmp/cron-env.txt 看真实环境 → 把所有路径和命令换成绝对路径 → 给命令加 >> log 2>&1 让错误现身 → 再检查 % 转义、时区、脚本换行符和执行位。绝大多数「crontab 不执行」都能在这五步里定位。还有个一劳永逸的习惯:crontab 里永远只放一行调用脚本的路径,把复杂逻辑都放进脚本,环境、日志、错误处理都在脚本里自己管。
或 cron 服务本身的问题。
源,从一开始就避开这个坑。
- 点赞
- 收藏
- 关注作者
评论(0)