Linux 设置周期性定时任务的常用系统工具是crontab,本文列举一些实用的例子。
目录
实例
这里是一些常用的例子:
描述
cron 语法
例子
一小时之内
每分钟执行
* * * * *
0:01,0:02,0:03,……23:59
每2分钟执行
*/2 * * * *
0:00,0:02,0:04,……23:58
每小时的2分执行
2 * * * *
0:02,1:02,2:02,3:02,……,23:02
每半小时执行
*/30 * * * *
0:00,0:30,1:00,1:30,2:00,……,23:30
分钟是50分的倍数时执行
*/50 * * * *
0:00,0:50,1:00,1:50,2:00,2:50,……
每17分钟执行
0:00,0:17,0:34,0:51,1:08,1:25,1:42,……
一天之内
每天整点执行
0 * * * *
或 @hourly
0:00,2:00,3:00,……23:00
每小时的15分执行
15 * * * *
0:15,2:15,3:15,……23:15
每天 12点5分 执行
5 12 * * *
12:05
每天 10点到18点 整点执行
0 10-18 * * *
10:00,11:00,12:00,……,18:00
每天 10点和18点 半点执行
30 10,18 * * *
10:30,18:30
从0点开始,每隔4小时 半点执行
30 */4 * * *
0:30,4:30,8:30,12:30,……
从1点开始,每隔4小时 半点执行
30 1-23/4 * * *
1:30,5:30,9:30,13:30,……
一周之内
每周六中午12点执行
0 12 * * 6
或 0 12 * * sat
每周六 12:00
每周二、四、六中午12点执行
0 12 * * 2-6/2
每周二、四、六 12:00
周末中午12点执行
0 12 * * sat,sun
每周六、日 12:00
每周日的凌晨0点执行
0 0 * * 0
或 @weekly
每周日 00:00
每周一、二 的 8点和12点执行
0 8,12 * * 1,2
每周一8:00,12:00,每周二8:00,12:00
一月之内
每月1日的凌晨0点执行
0 0 1 * *
或 @monthly
每月1日 00:00
每月25日的17点执行
0 17 25 * *
每月25日 17:00
每月的第一个周日执行
每月第一个周日
一年之内
每单数月份的25日的17点执行
0 17 25 */2 *
1月25日 17:00,3月25日 17:00
crontab 的形式
系统中有两个crontab:
系统级别
系统级别的 crontab 有两种形式: /etc/crontab 文件和 /etc/cron.d 目录下的文件,只有管理员能修改。和下面用户级别的 crontab 不同的是,这两套文件随系统自动存在,而不像 用户级别 的 crontab 一样需要安装。系统级别的 crontab 中的命令前带有用户名,相比之下,更为安全、更常用的是用户级别的 crontab:
用户级别
每个用户默认是没有crontab的,初次执行 crontab 命令时,系统将为这位用户安装 crontab 文件,然后可以使用 crontab -e 编辑 或者 crontab -l 来显示 crontab 文件内容。
crontab 文件中合法的语句只有两类:
环境变量
定时任务
crontab 文件环境变量
在定时命令前设置环境变量,以保证命令的正确执行。格式为 name=value
SHELL
比如 crontab 默认使用的 shell 是 /bin/sh ,如果想设为 bash,需要像下面这样设置:
SHELL=/bin/bash
PATH
crontab 默认的 PATH 是 /usr/bin:/bin ,而不是用户登录后所看到的 PATH 变量,所以如果你不愿意使用绝对路径调用命令,而且命令也不在前面这两个 PATH 中,那么需要事先修改 PATH 变量:
PATH=/your/specific/path
容易出错的是,crontab 中不能像其他shell文件一样做变量替换,所以在 crontab 中下面的写法将达不到目的:
PATH=/your/specific/path:$PATH # 错误示范
一个例外是,bash 中可以使用波浪线(~)表示用户的主目录(在 /etc/passwd 中规定的):
SHELL=/bin/bash
PATH=~/your/specific/path
HOME
命令被调起的起始路径,也就是 HOME 变量,是用户自己的主目录(在 /etc/passwd 中规定的)
MAILTO
当定时任务执行后,系统将给相关用户发站内邮件,如果不希望发出邮件,需要事先将 MAIL 命令定义为空值:
MAILTO=""
注意这里空值必须用引号表示,而不能只写一个等号
MAILTO= #错误示范
一个完整的例子
HOME=/home/yourname
PATH=/home/yourname/jdk/bin:/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin
SHELL=/bin/bash
MAILTO=""
*/1 * * * * command
crontab 时间语法
定时任务中有 6 个字段:
分钟 小时 日期 月份 星期 命令
前五个字段表示时间条件,可能的取值为:
*
星号表示:每个、不要求、无所谓、随便、无论、任意值、全部值、所有值、总是、从第一个可能的值到最后一个可能的值,对于小时字段来说, * 等效于 0-23;对于星期字段来说, * 等效于 0-6;对于月份字段来说, * 等效于 1-12
-
连字符表示范围(闭区间):比如 1-4 等效于 1,2,3,4
,
逗号表示:列表,可以列出所有希望的值,比如 1,2,3,4
-,-组合
逗号和连字符组合,比较容易理解:比如: 8-12, 14-18
/
斜杠 表示 “从第一个值开始,每*个”,比如小时中的 */4 表示从0点开始的每4小时, 1-7/4 等效于 1,5
名称
月份和星期字段还可以使用名称的头三个字母来增强可读性(大小写均可),比如: jan,wed
预设周期
@yearly 命令于每年1月1日(无论星期几)的凌晨0点执行,等效 0 0 1 1 *
@monthly命令于1日(无论几月、星期几)的凌晨0点执行, 等效 0 0 1 * *
@weekly 命令于星期日的凌晨0点执行,等效 0 0 * * 0
@daily命令于每日的凌晨0点执行,等效 0 0 * * *
@hourly命令于每小时的0分执行,等效 0 * * * *
日期和星期
如果日期和星期都有定义(非*号的值),那么将取 或 逻辑,只要满足任意一个条件即可执行。
crontab 命令格式
第六个字段是执行的命令,命令中的百分号 (%)会被认为是换行符,百分号以前的部分是执行的命令,以后的部分会被当做标准输入。
如果命令中必须包含百分号,则需要用反斜杠(\)转义,不然百分号将不起作用。比如正常情况下 date 命令的执行格式是:
$ date "+%Y%m%d"
到了 crontab 里就要写成:
25 8 * * * date "+\%Y\%m\%d"
crontab 不工作的原因
如果 crontab 不工作,可以到 /var/log/syslog 中查看原因。一般会有如下可能:
PATH 变量错误
上节 提到, PATH 默认是最小集: /usr/bin:/bin ,和用户自己定义 shell 里的 PATH 变量不同,所以即使用户自己在 shell 中可以正确执行,也不说明 cron 一定能找到需要执行的命令。
解决方案:在命令之前指定 PATH 变量
SHELL 的选择
上节 提到,SHELL 默认是 sh,所以如果一些命令只能在bash下执行,则需要预先设置 SHELL 变量
解决方案:在命令之前指定 SHELL 变量
邮件服务
上节 提到,执行命令后需要发出邮件,一些系统中未预先安装邮件命令。如果从 /var/log/syslog 中看到是和邮件相关的报错,可以尝试下面的方法:
解决方案:安装邮件的相关工具:
# sudo apt install mailutils
精细控制
crontab 的设计意图是精准的指定“(年,月,日,时,分)”的时间点坐标。
run this command at this time on this date. 在指定的日期,指定的时间点执行。
因为各种时间点坐标的进位周期各不相同(60分、24小时、30天、12月),所以一些只关注周期而忽略时间点坐标的需求,只靠原生的 cron 语法就不能达到目的了。需要 test 命令或者 cron 语法组合完成,比如:
配合 test 使用
每月第二个周六
0 4 8-14 * * test $(date +\%u) -eq 6 && echo "第二个周六"
解释:test 命令用来检验参数是否为 true,当日期在每月的8日到14日之间时,每天执行 test 表达式,当 $(date +\%u) 结果等于 6 时,就能断定当天是当月的第二个周六。
每隔17分钟
每分钟检查当前的分钟数是否能被17整除
用于监控 Jenkins agent 的例子