crontab 定时任务避坑指南:从写对第一条规则到日志排查

举报
yd_281047095 发表于 2026/11/02 12:03:20 2026/11/02
【摘要】 几乎每台 Linux 服务器上都跑着几条定时任务:每天凌晨备份数据库、每小时清理临时文件、每五分钟检查一次服务是否存活。

几乎每台 Linux 服务器上都跑着几条定时任务:每天凌晨备份数据库、每小时清理临时文件、每五分钟检查一次服务是否存活。cron 看起来简单,一行规则就能搞定,但"写了不跑""手动能跑、定时就失败"这类问题几乎每个人都踩过。这篇文章把 crontab 的常用写法和最常见的坑整理成一份清单,方便日常对照。

一、时间字段怎么读

一条 crontab 规则由 5 个时间字段加一条命令组成:

# 分 时 日 月 周  命令
  30  2  *  *  *  /opt/scripts/backup.sh
  • 分:0-59
  • 时:0-23
  • 日:1-31
  • 月:1-12
  • 周:0-7(0 和 7 都表示周日)

几个常用符号:

  • *:任意值
  • ,:列举,如 1,15 表示 1 号和 15 号
  • -:范围,如 9-18 表示 9 点到 18 点
  • /:步长,如 */5 表示每 5 个单位

常见例子:

*/5 * * * *    每 5 分钟
0 * * * *      每小时整点
0 9 * * 1-5    工作日早上 9 点
0 3 1 * *      每月 1 号凌晨 3 点

一个容易误会的点:日和周同时指定时,是"或"的关系。0 0 13 * 5 表示每月 13 号或每个周五,而不是"13 号恰好是周五"。

二、编辑与查看

crontab -e      # 编辑当前用户的定时任务
crontab -l      # 查看
crontab -u www -l   # 以 root 查看其他用户的任务

除了用户级 crontab,还有系统级的 /etc/crontab 和 /etc/cron.d/ 目录。系统级文件比用户级多一个"用户"字段:

# /etc/cron.d/cleanup
0 4 * * * root /opt/scripts/cleanup.sh

漏写这个字段,任务就不会按预期执行,这是从 crontab -e 迁移到 /etc/cron.d/ 时最常见的错误。

三、坑一:环境变量和命令行不一样

cron 执行任务时只带一个非常精简的环境,PATH 通常只有 /usr/bin:/bin。你在终端里能直接运行的 node、python3、docker,到了 cron 里可能就是"command not found"。

解决办法有三种,按推荐程度排序:

  1. 脚本里使用命令的绝对路径,用 which node 查到后写死;
  2. 在 crontab 顶部声明 PATH:
PATH=/usr/local/bin:/usr/bin:/bin
SHELL=/bin/bash
  1. 在脚本开头显式加载需要的环境,例如 source /etc/profile。

同理,工作目录也不是你以为的项目目录,而是用户的家目录。脚本里用到相对路径时,先 cd 到正确位置:

#!/bin/bash
cd /opt/app || exit 1
./run.sh

四、坑二:百分号要转义

在 crontab 的命令部分,% 有特殊含义(会被当作换行)。下面这条规则看起来没问题,实际会执行失败:

0 2 * * * tar czf /backup/db-$(date +%F).tar.gz /data

正确写法是把 % 转义成 \%:

0 2 * * * tar czf /backup/db-$(date +\%F).tar.gz /data

更省心的做法是把复杂命令都放进脚本,crontab 里只调用脚本。

五、坑三:任务重叠执行

如果一个每 5 分钟执行的任务某次跑了 8 分钟,下一次就会和上一次同时运行,可能导致重复处理数据或者文件锁冲突。用 flock 可以很简单地保证同一时间只有一个实例:

*/5 * * * * flock -n /tmp/sync.lock /opt/scripts/sync.sh

-n 表示拿不到锁就立即退出,不排队等待。

六、把输出记下来

cron 默认会把任务输出通过本地邮件发给用户,大多数服务器没有配置邮件,输出就直接丢了。建议每条任务都显式重定向日志:

30 2 * * * /opt/scripts/backup.sh >> /var/log/backup.log 2>&1

2>&1 把错误输出也写进同一个文件,排查时一目了然。日志文件记得配合 logrotate 定期轮转,避免越写越大。

七、任务没执行时怎么排查

按下面的顺序检查,基本能定位绝大多数问题:

  1. cron 服务是否在运行:systemctl status cron(CentOS 系为 crond)。
  2. 规则是否被加载:crontab -l 确认内容,注意文件最后一行要有换行。
  3. 系统日志里有没有触发记录:
grep CRON /var/log/syslog        # Debian/Ubuntu
grep CROND /var/log/cron         # CentOS/RHEL
journalctl -u cron --since today
  1. 脚本是否有执行权限:chmod +x script.sh,并确认首行 shebang 正确。
  2. 模拟 cron 环境手动执行:
env -i HOME=$HOME PATH=/usr/bin:/bin /bin/sh -c '/opt/scripts/backup.sh'

如果这样手动执行也失败,说明问题出在环境变量或路径上,而不是 cron 本身。

  1. 时区是否正确:cron 使用系统时区,用 timedatectl 确认。容器里的时区经常是 UTC,比北京时间晚 8 小时。

八、小结

写好一条定时任务,记住几条原则就够了:命令用绝对路径,复杂逻辑放进脚本,% 记得转义,长任务加 flock,输出一定要落日志。出问题时先看系统日志,再用精简环境复现。把这些习惯固定下来,cron 就会成为最省心的运维工具之一。

如果你的任务需要更精细的控制,比如依赖其他服务启动、失败自动重试,也可以考虑用 systemd timer 替代 cron,两者可以按场景搭配使用。

【声明】本内容来自华为云开发者社区博主,不代表华为云及华为云开发者社区的观点和立场。转载时必须标注文章的来源(华为云社区)、文章链接、文章作者等基本信息,否则作者和本社区有权追究责任。如果您发现本社区中有涉嫌抄袭的内容,欢迎发送邮件进行举报,并提供相关证据,一经查实,本社区将立刻删除涉嫌侵权内容,举报邮箱: cloudbbs@huaweicloud.com
  • 点赞
  • 收藏
  • 关注作者

评论(0)

0/1000
抱歉,系统识别当前为高风险访问,暂不支持该操作

全部回复

上滑加载中

设置昵称

在此一键设置昵称,即可参与社区互动!

*长度不超过10个汉字或20个英文字符,设置后3个月内不可修改。

*长度不超过10个汉字或20个英文字符,设置后3个月内不可修改。