crontab 主要用于需要管理周期执行定时任务的场景,比如定期备份数据、定时杀毒、定期清理垃圾文件等。 Linux中的cron进程是一个主要的系统调度进程,可以在后台自动完成用户指定的任务计划。它每分钟检查一遍各个用户的”任务计划书“,也就是crontab文件,如果计划书中所指定的运行条件满足,就立即为用户执行计划书中的任务。那么,这个计划书放在哪儿 呢?就放在/var/spool/cron/crontabs目录下面。
crontab 安装
(有些系统默认已经带了 crontab,无需安装的朋友可以直接跳过本节)
安装:
yum install -y vixie-cron
yum install -y crontabs
启动:
systemctl start crond.service
重启:
systemctl restart crond.service
设置开机启动:
systemctl enable crondservice
命令格式
通常,系统并不允许用户直接编辑计划书,/var/spool/cron/crontabs目录也只有root用户 才可读写。为了方便计划书的管理,系统提供了crontab命令:
crontab 主要有以下几种命令格式
crontab [-u user] file
crontab [-u user] [-l | -r | -e] [-i] [-s]
crontab -n [ hostname ]
crontab -c
命令参数:
- -u user:用来设定某个用户的crontab服务,例如,"-u ixdba"表示设定ixdba用户的crontab服务,此参数一般有root用户来运行。
- -file:file是命令文件的名字,表示将file做为crontab的任务列表文件并载入crontab。如果在命令行中没有指定这个文件,crontab命令将接受标准输入(键盘)上键入的命令,并将它们载入crontab。
- -e:编辑某个用户的crontab文件内容。如果不指定用户,则表示编辑当前用户的crontab文件。
- -l:显示某个用户的crontab文件内容,如果不指定用户,则表示显示当前用户的crontab文件内容。
- -r:从/var/spool/cron目录中删除某个用户的crontab文件,如果不指定用户,则默认删除当前用户的crontab文件。
- -i:在删除用户的crontab文件时给确认提示。
crontab -e
这个命令用于编辑定时任务列表,当我们输入完命令,按下回车键之后,它会使用默认编辑器(通常是vi/vim)打开一个文件,里面的内容可能是这样子的:
这很可能是你看到的,在设置任何定时任务之前,这里是看不到任何内容的,如果你已经设置了内容的话,那么看到的可能是这样的
这是我提前设置好的定时任务,我们暂时不解释这个配置的功能,但从这里可以知道,通过 crontab -e
我们可以编辑定时任务。
如果我们什么都不做,直接退出编辑器会看到以下提示:
如果我们修改了这个文件,比如增加了一个任务
保存退出之后,我们可以看到成功的提示:
如果说,我们的配置有误,那么系统就会提示我们, 重新编辑,你可以输入 y
重新编辑 或者 n
放弃刚刚的配置的内容
crontab -l
这个命令可以列出当前的定时任务内容, 这与我们使用 crontab -e
看到的内容一样,不同的是 crontab -e
可以编辑,而这里只能查看
crontab -r
这个命令用于删除任务列表里面的内容(在删除之前我们先做一个备份)
通过上面的示例可以看出,执行完 crontab -r
之后,我们的任务列表被清空了
crontab file
这个命令用于将保存在某个文件中的任务列表中的内容覆盖到我们的任务列表中,我们刚刚在删除任务列表前做了备份
现在来看一下,使用命令能否将任务列表还原回去
可以看到,通过 crontab file
命令,我们将刚刚备份的文件内容恢复到任务列表当中了。
有两点需要注意:
- 这个命令的操作很粗暴,会用指定文件的内容直接覆盖任务列表,使用前一定要想清楚,最好在操作前进行备份
- 用于覆盖的文件内容必须是合法的内容,如果语法有误,内容将不会更新,且会得到下图所示的错误提示
crontab -ri
这个命令用于删除任务列表里面的内容,但会在删除之前让你确认是否删除
你可以输入 y
确认删除,也可以输入 n
取消这次操作
crontab -u user_name
这里我们补充一点,Linux 中的每个用户都可以有自己的定时任务,他们设置的任务被保存在 /var/spool/cron/
目录下的同名文件中
这个命令跟 -i
一样,需要与其它命令配合使用
crontab [-u user] file
crontab [-u user] [-l | -r | -e] [-i] [-s]
不使用 -u
时默认的就是当前用户,如果你要配置其它用户的任务列表
就可以使用这个命令
crontab -u user -e
当然,使用这个命令的前提是要有对应文件的操作权限,大多数情况下,这个命令都是 root 在用。
需要注意的是,根据文档提示,如果你从一个普通用户
su
到其它用户,在进行crontab 命令时,就一定要加上-u
选项。但我实验发现,su
到其它用户之后,再进行 crontab 操作,默认使用的 su 之后的用户。
注意:
1. crontab 文件名,提交了新计划文件之后,原来的计划是否还在呢?答案是否定的。这 种方法进行的是完全覆盖,而非追加。同时要说明的是,当运行命令:crontab newplan.txt 之后,系统复制了一份newplan.txt的内容用来创建该用户的计划书,存 放到/var/spool/cron/crontabs目录下,newplan.txt与计划之间并无联系。但建议将其 保留,作为计划书的副本。当要修改计划时,可先修改newplan.txt,然后再提交为新计划。
2.计划书的输出和日志,如果用户的计划书在运行时有输出,用户是无法直接从终端上看 到的。cron进程会将执行计划时产生的所有输出数据和错误信息发送到指定用户的邮箱 ,用户可到邮箱中去查看,所以建议在计划中把有用的输出数据重定向到文件中。要想 查看各个计划的执行情况,可以查看cron进程的日志文件:/var/log/cron。
3.更简单的任务计划, 如果觉得这样麻烦,还有一种简单的方法。/etc下面有4个目录: cron.hourly,cron.daily,cron.weekly,cron.weekly,这4个目录下脚本的执行周期 分别是每小时,每天,每周,每月。根据自己的需要,将要运行的脚本直接放置到对应 的目录下即可,系统会自动为你完成任务。
任务列表的语法
Crontab命令时间格式设置
* * * * * command
分 时 日 月 周 命令
使用 crontab -e
无需指定用户名称,因为这个命令就是使用用户自己的身份来执行的。
补充: /etc/crontab 中的内容只能由 root 来设置,一般用于设置系统级的周期任务
从上面的图里面可以知道,周期任务的配置语法由两部分组成(使用 contab -e
时忽略 user-name)
- 时间规则
- 要执行命令或者脚本
时间规则
前面5个 * 分别代表 分、时、日、月、周
- 第一个 * 代表每一分钟,也可以是 0-59 区间中的数字
- 第二个 * 代表每个小时,也可以是 0-23 区间中的数字
- 第三个 * 代表一个月中的每一天,也可以是 1-31 区间中的数字
- 第四个 * 代表一年中的每个月, 也可以是 1-13 区间中的数字,或者使用英文 jan,feb,mar,apr... 等来表示
- 第五个 * 代表一周中的每一天, 也可以是 0-6 区间中的数字(星期天使用 0 或者 7 表示),也可以使用 sum,mon,tue,wed,thu,fri,sat 来表示
除了上面的配置方式之外,crontab 还支持更灵活的配置方式:
*
代表取值范围内的所有数字,如在分钟单位,则表示每分钟执行一次,其它时间点同理。第3段上的"*"代表[01-31]日,第4段上的"*"代表[01-12]月;,
用于列举多个数字,如1,3,5
指定1,3,5这三个时间点;-
用于确定时间区间,如2-6
等价于2,3,4,5,6;
- /代表每的意思,*/5表示每5个单位,如在分钟位置设置
*/2
表示每两分钟执行一次
注意,上述符号中的非标准符号不一定能在你的机器上正常运行,在使用前一定要先进行测试
命令
可以是shell命令或者执行某个已经写好的脚本
实例
以下举几个实例的例子
表示每分钟执行一次
* * * * * cmd
每个小时的0分和30分执行各执行一次
0,30 * * * * * cmd
每天的2点到5点每个小时的整点执行
0 2-5 * * * cmd
每年的 1月1日0点执行
0 0 1 1 * cmd
每天的12点到18点每隔3小时执行一次
0 12-18/3 * * * cmd
每个月最后的天的22点整执行(非标准语法,要先进行测试再投入生产环境)
0 22 L * * cmd
每晚的21:30重启apache
30 21 * * * /usr/local/etc/rc.d/lighttpd restart
每月1、10、22日的4 : 45重启apache
45 4 1,10,22 * * /usr/local/etc/rc.d/lighttpd restart
每周六、周日的1 : 10重启apache
10 1 * * 6,0 /usr/local/etc/rc.d/lighttpd restart
每天18 : 00至23 : 00之间每隔30分钟重启apache
0,30 18-23 * * * /usr/local/etc/rc.d/lighttpd restart
每星期六的11 : 00 pm重启apache
0 23 * * 6 /usr/local/etc/rc.d/lighttpd restart
每一小时重启apache
*/1 * * * /usr/local/etc/rc.d/lighttpd restart
晚上11点到早上7点之间,每隔一小时重启apache
23-7/1 * * * /usr/local/etc/rc.d/lighttpd restart
每月的4号与每周一到周三的11点重启apache
0 11 4 * mon-wed /usr/local/etc/rc.d/lighttpd restart
一月一号的4点重启apache
0 4 1 jan * /usr/local/etc/rc.d/lighttpd restart
每天早上7点执行一次 /bin/ls
0 7 * * * /bin/ls
在 12 月内, 每天的早上 6 点到 12 点中,每隔3个小时执行一次 /usr/bin/backup
0 6-12/3 * 12 * /usr/bin/backup
周一到周五每天下午 5:00 寄一封信给 alex@domain.name
0 17 * * 1-5 mail -s "hi" alex@domain.name < /tmp/maildata
每月每天的午夜 0 点 20 分, 2 点 20 分, 4 点 20 分....执行 echo "haha"
20 0-23/2 * * * echo "haha"
每个星期一凌晨执行
0 0 * * 1 echo Monday >> /home/test.txt
cron.allow 与 cron.deny
执行cron任务的权限是可以通过 /etc/cron.allow
和 /etc/cron.deny
两个文件进行配置。
- cron.allow 用于配置哪些用户可以使用 crontab
- cron.deny 用于配置哪些用户禁止使用 crontab
这两个文件的内容为每一行一个用户名,或者为空
- 如果 cron.allow 文件存在的话,需要限权的用户名必须在这个文件里面
- 如果 cron.deny 文件存在的话,需要权限的用户不能出现在这个文件里面
- 如果两个文件都不存在的话,则只有 root 有权限使用 crontab
如果两个文件都存在,/etc/cron.allow优先。当上述两个文件都不存在时,一个普通使用执行 crontab 命令会得到以下错误
环境变量
cron进程执行任务时,并不加载计划书所属用户的环境变量,只加载几个最基本的环境变量,比如执行任务的sh,$HOME,$MAILTO等。这几个环境变量的定义是在 /etc/crontab文件中。其中$MAILTO是指定计划执行过程中发生错误或者有数据输出时发送邮件到哪个用户。
在实际使用过程中, 我们都会编辑好一个.sh
文件,设置好权限(一般是增加执行权限 chmod +x task.sh
)。测试成功之后,兴高采烈地把它添加到 crontab 的任务列表里面,结果迟迟没有得到预期结果。我之前碰到这样的情况,直接执行脚本没问题,但使用 crontab 执行却报错,查看日志发现是环境变量的问题。
解决的办法很简单,只要在脚本内提前导入环境变量即可:
执行结果保存
如果crontab不重定向输出,并且crontab所执行的命令有输出内容的话,是一件非常危险的事情。因为该输出内容会以邮件的形式发送给用户,内容存储在邮件文件
/var/spool/mail/$user
如果命令执行比较频繁(如每分钟一次),或者命令输出内容较多,会使这个邮件文件不断追加内容,文件越来越大。而邮件文件一般存放在根分区,根分区一般相对较小,所以会造成根分区写满而无法登录服务器。
可以在配置任务的时候,在最后加入以下将执行过程中输出的内容保存到自己想要的地方。
*/5 * * * * cmd > /var/log/cron_task.log 2>&1 &
名词解释
在shell中,每个进程都和三个系统文件相关联:标准输入stdin,标准输出stdout和标准错误stderr,三个系统文件的文件描述符分别为0,1和2。所以这里2>&1的意思就是将标准错误也输出到标准输出当中。
> 就相当于 1> 也就是重定向标准输出,不包括标准错误。通过2>&1,就将标准错误重定向到标准输出了(stderr已作为stdout的副本),那么再使用>重定向就会将标准输出和标准错误信息一同重定向了。如果只想重定向标准错误到文件中,则可以使用2> file。
不输出内容
*/5 * * * * /root/XXXX.sh &>/dev/null 2>&1
将正确和错误日志都输出到 /tmp/load.log
*/1 * * * * /root/XXXX.sh > /tmp/load.log 2>&1 &
只输出正确日志到 /tmp/load.log
*/1 * * * * /root/XXXX.sh > /tmp/load.log & 等同于 */1 * * * * /root/XXXX.sh 1>/tmp/load.log &
只输出错误日志到 /tmp/load.log
*/1 * * * * /root/XXXX.sh 2> /tmp/load.log &
日志文件
我们可以查看 /var/log/cron
文件的内容来查看服务器执行了哪些任务
(我的是CentOS, 如果是Ubuntu可以到/var/log/cron.log
查看)
待补充
以下几点是我看了文档之后还不太明白的几点(主要还是英文水平还不够。。)
- crontab [-u user] -s
- crontab -n [hostname]
- crontab -c
- /etc/crontab 和 /etc/cron.d 文件内也可以设置任务列表,具体的使用场景我还没有接触过
以上所有内容是结合自己的实践与官方文档加上网友们的文章写成,还有很多自己不理解的,希望看到的朋友如果有知道的也评论告诉我哦,谢谢啦
ReadMore
man cron
man crontab
- crontab校验工具及语法介绍
- crontab 脚本错误日志和正确的输出写入到文件