Linux crontab 定时任务不执行的排查与实践

8 ℃ 0 条
内容摘要定时任务写进 crontab 却始终不执行,是运维最常遇到的困惑。多数情况并不是 cron 没跑,而是环境变量、路径、权限三者之一出了问题。本文按先看系统日志、再查环境变量、最后核对表达式的顺序,给出可直接照做的排查流程,并附可复用的配置示例。
Linux crontab 定时任务不执行的排查与实践

Linux crontab 定时任务排查流程示意图

定时任务写进 crontab 却始终不执行,是运维最常遇到的困惑。多数情况并不是 cron 没跑,而是环境变量、路径、权限三者之一出了问题。本文按「先看日志 → 再查环境 → 最后验证表达式」的顺序给出可复现的排查流程。

一、先确认任务到底有没有被调度

1. 从系统日志里找执行痕迹

排查第一步不是改配置,而是确认 cron 有没有真的触发。执行 grep CRON /var/log/syslog(CentOS 系为 /var/log/cron),能看到调度记录与执行用户。若有 CMD 行,说明任务已被调度,问题出在脚本内部;若完全没有记录,才需怀疑表达式或服务状态。

2. 用重定向捕获脚本输出

cron 默认把脚本的 stdout 与 stderr 邮寄给用户,个人服务器一般没配邮件,输出就彻底丢失,看起来像「没执行」。给每行任务显式加日志重定向,把退出码一并记下:

*/5 * * * * /bin/bash /opt/backup.sh >> /var/log/backup.log 2>&1; echo "exit:$?" >> /var/log/backup.log

确认 cron 与 crond 服务处于运行状态后,再看日志文件里是否有新的写入。

二、环境变量与路径是最常见的失败原因

1. PATH 被裁剪成只有三个目录

这是 crontab 第一大坑。cron 启动的 shell 不加载 .bashrc 与 .bash_profile,默认 PATH 通常只有 /usr/bin:/bin。脚本里用了 php、docker、node 这类装在 /usr/local/bin 的命令,手工执行正常,放进 crontab 就报 command not found。解决办法是在 crontab 顶部显式声明,或直接写绝对路径:

PATH=/usr/local/bin:/usr/bin:/bin
SHELL=/bin/bash
*/5 * * * * /usr/bin/php /var/www/app/artisan schedule:run >> /var/log/laravel.log 2>&1

2. 工作目录与用户身份不一致

cron 执行时的当前目录是执行用户的家目录,脚本里写相对路径 ./data 必然找不到文件。所有路径改成绝对路径,或在脚本开头 cd /opt/app。另外要核对任务所属用户:写在 /etc/crontab 里的任务必须指定用户列,写在用户 crontab 里的则不能带用户列,多写一列会导致整行被拒绝执行。

三、表达式与权限的最后把关

1. cron 表达式字段与常见误写

标准 crontab 是五个字段:分、时、日、月、周,分别对应 0-59、0-23、1-31、1-12、0-7(0 与 7 都表示周日)。最容易写错的是「日」与「周」同时指定——此时两者是或关系,不是与关系。表达式里也不能缺少空格分隔,*/5 * * * * 写成 */5* * * * 会被直接判为非法。

2. 系统级目录与文件权限

除 crontab -e,还可把脚本放进 /etc/cron.d/。该目录下的文件必须带用户列,且文件名不能含点号,否则会被静默忽略。脚本自身要 chmod +x;若由 root 写入、以 www 用户执行,还需确认目录与文件对该用户可读可执行。

关键配置提示

  • crontab 顶部统一声明 PATH 与 SHELL,脚本内一律使用绝对路径。
  • 每行任务都带 >> 日志 2>&1,先让失败有痕迹,再谈修复。
  • 改完表达式用 crontab -l 回读确认,避免编辑器层级的误改。

发表评论 (已有0条评论)

快来评论,快来抢沙发吧~