回到首页

输入关键词,多个关键词用空格分隔。

← 命令行与工程工具 · 系列目录

Crontab 指南:周期任务与执行环境

约 8 分钟更新于 2026-11-06
本页目录

Crontab 是 Unix/Linux 中用于设置周期执行指令的命令。如果我们需要定期执行某些任务,除了让任务常驻外,更方便的方法是让 crontab 来帮助我们调度执行。


更新记录

  • 2016.07.26: 初稿

简介

cron 是 Unix/Linux 中提供定期执行 shell 命令的服务,包括 crond 和 crontab 两部分:

  • crond: cron 服务的守护进程,常驻内存负责定期调度
  • crontab: cron 的管理工具,负责编辑调度计划

原稿演示在 Ubuntu 16.04 下进行。这里使用 Unix 五字段 crontab 语法,服务名、日志位置和扩展语法请以目标系统的手册为准。基本的使用方法可以用命令 man crontab 查看

NAME
       crontab - maintain crontab files for individual users (Vixie Cron)

SYNOPSIS
       crontab [ -u user ] file
       crontab [ -u user ] [ -i ] { -e | -l | -r }

简单解释一下

  • -e 编辑,类似 vim,保存退出时会检查语法
  • -l 列举所有任务
  • -r 删除所有任务

如果 crontab 运行出错,可以查看日志文件/var/log/syslog

基本语法

cron 的语法非常简单,一共分六大块,其中前五块用于指定时间周期,最后一块是具体执行的命令,看起来大概是这么个格式:

min hour day month week command

其中

  • min 表示分钟,范围 0-59
  • hour 表示小时,范围 0-23
  • day 表示天,范围 1-31
  • month 表示月,范围 1-12
    • 每个月的最后一天 crontab 本身是不支持的,需要通过脚本判断
  • week 表示周,范围 0-7
    • 这里 0 和 7 都表示周日
    • 在 Vixie/Cronie 风格实现中,日与星期都受限时,通常满足任一即可触发;不要把它们误读为同时满足
  • command 表示具体要执行的命令(最好是绝对路径)
    • 如果有多条命令,则可写入脚本按顺序执行;需要前一条成功才继续时用 &&,不要用表示后台运行的 & 来表达顺序。

另外,类似正则表达式,还有一些特殊符号帮助我们实现灵活调度

  • * 星号,表示每个可能的值都接受
    • 例如 * * * * * command 表示每分钟都执行 command 一次
  • , 逗号,并列时间
    • 例如 0 6,12,18 * * * command 表示在 6 点、12 点和 18 点整各执行 command 一次
  • - 减号,连续区间
    • 例如 * 9-17 * * * command 表示从 09:00 到 17:59,每分钟都执行 command 一次
  • / 斜线,间隔单位
    • 例如 */5 * * * * command 表示每隔 5 分钟执行 command 一次

系统级 Crontab

如果我们需要执行一些权限较高的指令,就需要利用 root 权限来执行,这时的机制和前面介绍的基本语法也是有区别的,我们需要编辑的文件是 /etc/crontab。先来看看其内容

dawang@dawang-Parallels-Virtual-Platform:~$ cat /etc/crontab
# /etc/crontab: system-wide crontab
# Unlike any other crontab you don't have to run the `crontab'
# command to install the new version when you edit this file
# and files in /etc/cron.d. These files also have username fields,
# that none of the other crontabs do.

SHELL=/bin/sh
PATH=/usr/local/sbin:/usr/local/bin:/sbin:/bin:/usr/sbin:/usr/bin

# m h dom mon dow user command
17 * * * * root cd / && run-parts --report /etc/cron.hourly
25 6 * * * root test -x /usr/sbin/anacron || ( cd / && run-parts --report /etc/cron.daily )
47 6 * * 7 root test -x /usr/sbin/anacron || ( cd / && run-parts --report /etc/cron.weekly )
52 6 1 * * root test -x /usr/sbin/anacron || ( cd / && run-parts --report /etc/cron.monthly )
#

我们需要在命令和时间间隔之间添加命令执行者,并且也可以添加环境变量在调度中使用。我们看到配置文件中有几个 cron.* 文件,先来看看还有什么类似的文件

dawang@dawang-Parallels-Virtual-Platform:~$ ll /etc | grep cron
-rw-r--r-- 1 root root 401 12月 29 2014 anacrontab
drwxr-xr-x 2 root root 4096 4月 21 06:14 cron.d/
drwxr-xr-x 2 root root 4096 4月 21 06:14 cron.daily/
drwxr-xr-x 2 root root 4096 4月 21 06:08 cron.hourly/
drwxr-xr-x 2 root root 4096 4月 21 06:14 cron.monthly/
-rw-r--r-- 1 root root 722 4月 6 05:59 crontab
drwxr-xr-x 2 root root 4096 4月 21 06:14 cron.weekly/

其中

  • cron.d 目录:读取该目录中符合命名与权限要求的配置文件,通常不递归子目录
  • cron.deny:限制哪些用户可以使用 crontab 管理工具,不等同于停止其已有任务
  • cron.allow:记录允许使用 crontab 管理工具的用户,这个文件的优先级较高,一般来说只需要配置一个文件即可(看是需要白名单还是黑名单机制)
  • cron.daily/hourly/monthly/weekly 目录:里面都是脚本,分别在指定的时间里执行

更多详细介绍,可以输入 man 5 crontab 或 man 8 cron 查阅

配置与服务管理

crontab -e 安装的是当前用户的调度表;/etc/crontab 和 /etc/cron.d/ 中的系统表多一个执行用户名字段,不能混用格式。需要管理其他用户的表时,应使用相应权限和 crontab -u,不直接编辑 spool 文件。

服务名可能为 cron 或 crond,日志可能进入 syslog 或 journal,不能把一种发行版的命令照搬到所有机器。使用 crontab -e 正常保存后,常见实现会重新载入配置,无须为每次修改重启服务。

执行环境通常比交互终端简单。明确工作目录、PATH、解释器和输出位置,避免任务在终端成功、定时执行却失败。还应考虑时区、夏令时以及前一次任务未结束时的重叠执行。

实例测试

接着我们来实战一下,第一次使用 crontab -e 需要我们选择编辑器,默认是 nano,但是我选择了 vim

dawang@dawang-Parallels-Virtual-Platform:~$ crontab -e
no crontab for dawang - using an empty one

Select an editor. To change later, run 'select-editor'.
  1. /bin/ed
  2. /bin/nano <---- easiest
  3. /usr/bin/vim.tiny

Choose 1-3 [2]:

为了验证真的在执行,我们建立两个每分钟都执行的操作,具体如下(主要关注最后两行):

# Edit this file to introduce tasks to be run by cron.
#
# Each task to run has to be defined through a single line
# indicating with different fields when the task will be run
# and what command to run for the task
#
# To define the time you can provide concrete values for
# minute (m), hour (h), day of month (dom), month (mon),
# and day of week (dow) or use '*' in these fields (for 'any').#
# Notice that tasks will be started based on the cron's system
# daemon's notion of time and timezones.
#
# Output of the crontab jobs (including errors) is sent through
# email to the user the crontab file belongs to (unless redirected).
#
# For example, you can run a backup of all your user accounts
# at 5 a.m every week with:
# 0 5 * * 1 tar -zcf /var/backups/home.tgz /home/
#
# For more information see the manual pages of crontab(5) and cron(8)
#
# m h dom mon dow command
* * * * * date >> /home/dawang/date.txt
* * * * * echo "time to go!" >> /home/dawang/time.txt

这里做了两件事,一个是每分钟报时,另一个就是每分钟输出一段话,这里使用 >> 表示追加输出,更多输入输出方式在下一节有介绍。确认目标系统的 cron 服务已启动后,等待一段时间,就可以看到输出啦,具体参考下面的命令,这里就不赘述了:

dawang@dawang-Parallels-Virtual-Platform:~$ ll | grep txt
-rw-rw-r-- 1 dawang dawang 1849 7月 26 16:08 date.txt
-rw-rw-r-- 1 dawang dawang 516 7月 26 16:08 time.txt
dawang@dawang-Parallels-Virtual-Platform:~$ tail -n 10 date.txt
2016年 07月 26日 星期二 16:01:01 CST
2016年 07月 26日 星期二 16:02:01 CST
2016年 07月 26日 星期二 16:03:01 CST
2016年 07月 26日 星期二 16:04:01 CST
2016年 07月 26日 星期二 16:05:01 CST
2016年 07月 26日 星期二 16:06:01 CST
2016年 07月 26日 星期二 16:07:01 CST
2016年 07月 26日 星期二 16:08:01 CST
2016年 07月 26日 星期二 16:09:01 CST
2016年 07月 26日 星期二 16:10:01 CST
dawang@dawang-Parallels-Virtual-Platform:~$ tail -n 10 time.txt
time to go!
time to go!
time to go!
time to go!
time to go!
time to go!
time to go!
time to go!
time to go!
time to go!

重定向命令

文件描述符数字必须与 > 连在一起:2> 是标准错误重定向,2 > 则会把 2 当成普通参数。

command > output.txt          # 标准输出覆盖写入
command >> output.txt         # 标准输出追加
command 2> error.txt          # 标准错误覆盖写入
command > output.txt 2>&1     # 两种输出写入同一文件
command < input.txt           # 从文件读取标准输入

重定向按从左到右处理,> output.txt 2>&1 与 2>&1 > output.txt 不等价。更多说明见 Bash 重定向手册。

参考链接

补充:重叠执行与补跑

cron 到点启动任务,不会自动保证同一任务只有一个实例。运行时间可能超过调度间隔时,应明确选择跳过、排队还是允许并发,并用锁或应用层协调实现。跨主机执行时,单机文件锁并不足够。

任务还应尽量允许重试。例如按日期生成报表,可用日期作为结果标识,避免重跑产生重复记录。停机期间错过的任务是否补跑,取决于所用调度系统,不能默认普通 cron 有持久队列。日志也需要轮转,并检查失败状态,而不只是确认文件存在。

相关文章