cron表达式是类Unix系统上配置定时任务的核心语法,五个字段决定了任务何时执行。看似简单,实际写起来却很容易出错:有人想让任务每周一早上八点跑一次,结果周日也触发了;有人想每5分钟执行一次,结果写成了每小时的第5分钟执行。这些问题的根源都是对cron各字段含义理解不透彻。本文从语法结构入手,把五个字段、四种特殊符号逐一讲清楚,并配上常见场景的对照表和易错点分析。

cron表达式的五段式结构
标准的cron表达式由五个字段组成,从左到右依次是分钟、小时、日(一个月中的第几天)、月份、星期(一周中的第几天),字段之间用空格分隔。每个字段都有自己的取值范围,写表达式之前必须先把这些范围记牢。
各字段的取值范围如下:分钟字段取值0到59,表示一小时内的第几分钟;小时字段取值0到23,采用24小时制;日字段取值1到31,表示当月第几天,注意大月小月的实际天数会影响任务是否触发;月份字段取1到12,也可以用英文缩写jan到dec;星期字段取0到7,其中0和7都表示星期日,1到6对应星期一到星期六,同样支持mon、tue等缩写。
一个完整的crontab配置行看起来是这样的:
# 分钟 小时 日 月 星期 要执行的命令 # 下面表示每天凌晨2点30分执行备份脚本 30 2 * * * /home/user/backup.sh # 查看当前用户已有的定时任务 crontab -l
这里要注意,crontab配置行中表达式后面跟的是具体命令,表达式本身只负责时间。另外,编辑定时任务统一用crontab -e命令,编辑器中每行一条任务,空行和以#开头的行会被忽略。新手常犯的错误是直接去改系统的/etc/crontab文件,这个文件的格式与用户crontab不同,它多了一个用户名字段,写在表达式之后、命令之前,直接复制网上的用户级写法进去会执行失败。
四种特殊符号的用法与区别
星号(*)表示任意值,即该字段不做限制。比如分钟字段写*,意味着每一分钟都匹配。五个字段全是星号的表达式* * * * *表示每分钟执行一次任务,这是验证cron是否正常工作的常用测试写法。
逗号(,)用于列举多个离散值。分钟字段写0,15,30,45表示每小时的第0、15、30、45分钟各执行一次。逗号可以混合使用单个值和区间,例如1-5,20,30表示匹配1到5分钟、第20分钟和第30分钟。注意逗号前后不要加空格,否则会被解析成下一个字段,导致整个表达式错位。
连字符(-)表示连续区间。小时字段写9-17表示从早上9点到下午5点的每个小时。月份写jun-aug表示六、七、八月。区间必须是从小到大,写反了如17-9在标准cron中不会按预期工作。
斜杠(/)表示步长,通常配合星号或区间使用。*/5在分钟字段表示从0开始每隔5分钟,即0、5、10、15直到55;*/10在小时字段表示0点、10点、20点。这里有个非常常见的误区:*/15在小时间隔上得到的是0点、15点、30点、45点,而不是从任务创建时刻开始每15小时。cron的步长永远基于字段的最小值起算,不存在“从现在开始每隔N”的语义。
# 每5分钟执行一次 */5 * * * * /usr/bin/monitor.sh # 每小时的前30分钟内,每10分钟执行一次 0-30/10 * * * * /usr/bin/monitor.sh # 语法错误示例:逗号后多了空格 */5 * * * , * /usr/bin/task.sh
高频场景配置对照
掌握语法之后,更重要的是能快速写出实际业务需要的表达式。下面这张表覆盖了运维和开发中最常见的定时需求,可以直接对照使用。
| 需求描述 | 表达式 |
|---|---|
| 每分钟执行一次 | * * * * * |
| 每5分钟执行一次 | */5 * * * * |
| 每小时第30分钟执行 | 30 * * * * |
| 每天凌晨3点执行 | 0 3 * * * |
| 每天早上8点30分执行 | 30 8 * * * |
| 每周一上午9点执行 | 0 9 * * 1 |
| 每月1号凌晨0点执行 | 0 0 1 * * |
| 工作日(周一到周五)上午9点执行 | 0 9 * * 1-5 |
| 每周一到周五,每半小时执行 | 0,30 9-18 * * 1-5 |
表中最后一条值得展开说明:分钟字段0,30配合小时区间9-18,实现了工作时间内每半小时采集一次的需求。这说明cron的字段之间是“与”的关系,所有字段同时匹配时任务才会触发,理解这一点就能灵活组合出各种复杂调度。
容易被忽视的坑与排错方法
第一个坑是日和星期的联合匹配问题。当表达式中日字段和星期字段都不为*时,标准cron的行为是“或”而非“与”。例如0 0 1 * 1的本意可能是“每月1号且是星期一才执行”,但实际效果是“每月1号执行,且每个星期一也执行”,触发次数远超预期。如果必须实现严格的与逻辑,要么把判断放进脚本内部处理,要么改用支持该语义的调度系统。
第二个坑是时区与环境变量。crond读取的是服务器系统时区,如果服务器是UTC时间而你按北京时间写表达式,任务会在错后8小时的时间点触发。另外cron执行任务时的环境变量非常精简,PATH往往只有/usr/bin:/bin,脚本里引用的第三方命令最好写绝对路径,否则任务在终端手动跑没问题、放进cron就静默失败。同理,脚本中的相对路径要改为绝对路径,因为cron的工作目录通常不是脚本所在目录。
第三个坑是秒级精度。传统五段式cron最小粒度是分钟,做不到每30秒执行一次。如果确有秒级需求,可以在脚本内部用循环配合sleep实现,或者改用六段式cron(Spring的@Scheduled、Quartz都支持在最前面增加秒字段),六段式写法为秒 分 时 日 月 星期,例如*/30 * * * * ?在Quartz中表示每30秒执行,其中问号表示放弃指定该字段。
排错时建议先看日志:Debian系发行版的cron日志在/var/log/syslog中,可以用grep CRON /var/log/syslog筛选记录;CentOS系需要先开启cron日志(编辑/etc/rsyslog.conf去掉cron行的注释)。如果日志显示命令确实执行了但结果不对,问题多半出在环境变量或路径上;如果日志里压根没有记录,就要检查表达式本身或crond服务是否启动。掌握这些排查思路,配合前面讲的语法规则,绝大多数定时任务问题都能快速定位。
cron表达式定时任务Linux crontab修改时间:2026-09-16 20:00:48