【Linux命令022】定时任务crontab

Scroll Down

前言

这是一篇丢失在时间长河又突然回归的文章,被scp基金会在几个月前收容,又在2020年10月14日确认无危险性,因此回归本公众号。

参考文档:

正文

怎么在Linux下定时启动某个任务?

例如自动备份mysql数据库,每天更新外部接口数据?

在Linux下有个与windows下的计划任务类似的工具,即crond。

crond 是linux下一般默认安装并自启动的服务工具,crond进程每分钟会定期检查是否有要执行的任务,如果有要执行的任务,则自动执行该任务。

如果你的Linux系统中没有此服务,可以安装一下。

yum install crontabs

在Linux下的任务调度分为两类,系统任务调度和用户任务调度。

系统任务调度:系统周期性所要执行的工作,比如写缓存数据到硬盘、日志清理等。在/etc目录下有一个crontab文件,这个就是系统任务调度的配置文件。

用户任务调度:用户定期要执行的工作,比如用户数据备份、定时邮件提醒等。所有用户定义的crontab 文件都被保存在 /var/spool/cron目录中。其文件名与用户名一致。

而使用crond的控制命令则是crontab

什么是crontab?

首先看下cronttab的使用说明

[root@localhost ~]# crontab --help
crontab:无效选项 -- -
crontab: usage error: unrecognized option
Usage:
 crontab [options] file
 crontab [options]
 crontab -n [hostname]

Options:
 -u <user>  define user
 -e         edit user's crontab
 -l         list user's crontab
 -r         delete user's crontab
 -i         prompt before deleting
 -n <host>  set host in cluster to run users' crontabs
 -c         get host in cluster to run users' crontabs
 -s         selinux context
 -x <mask>  enable debugging

Default operation is replace, per 1003.2

crontab 是用来让使用者在固定时间或固定间隔执行程序之用,换句话说,也就是类似使用者的时程表。

常用参数说明
-u user是指设定指定 user 的时程表,这个前提是你必须要有其权限(比如说是 root)才能够指定他人的时程表。如果不使用 -u user 的话,就是表示设定自己的时程表。
-e执行文字编辑器来设定时程表,内定的文字编辑器是 VI,如果你想用别的文字编辑器,则请先设定 VISUAL 环境变数来指定使用那个文字编辑器(比如说 setenv VISUAL joe)
-r删除目前的时程表
-l列出目前的时程表

查看下/etc/crontab 文件,内容如下:

[root@izbp117mtgmllet9ryobawz ~]# cat /etc/crontab
SHELL=/bin/bash
PATH=/sbin:/bin:/usr/sbin:/usr/bin
MAILTO=root

# For details see man 4 crontabs

# Example of job definition:
# .---------------- minute (0 - 59) 分钟
# |  .------------- hour (0 - 23) 小时
# |  |  .---------- day of month (1 - 31) 一个月中的第几天
# |  |  |  .------- month (1 - 12) OR jan,feb,mar,apr ... 月份
# |  |  |  |  .---- day of week (0 - 6) (Sunday=0 or 7) OR sun,mon,tue,wed,thu,fri,sat 星期
# |  |  |  |  |
# *  *  *  *  * user-name  command to be executed
  • 第一行SHELL变量指定了系统要使用哪个shell,这里是bash;
  • 第二行PATH变量指定了系统执行命令的路径;
  • 第三行MAILTO变量指定了crond的任务执行信息将通过电子邮件发送给root用户,如果MAILTO变量的值为空,则表示不发送任务执行信息给用户。
  • 星号(*):代表所有可能的值,如month字段为星号,则表示在满足其它字段的制约条件后每月都执行该命令操作。
  • 逗号(,):可以用逗号隔开的值指定一个列表范围,例如,“1,2,5,7,8,9”
  • 连字符(-):连字符定义范围。例如,2000-2010 表示2000年至2010年期间的每年,包括2000年和2010年。
  • 正斜线(/):可以用正斜线指定时间的间隔频率,例如“0-23/2”表示每两小时执行一次。

小 结:

  • 周和日最好不要同时用
  • 定时任务要加注解
  • 可以定向到日志文件或者空文件
  • 定时任务一定是绝对路径,且目录必须存在才能出结果
  • crontab 服务一定要开启运行

cron表达式工具

我们有时很容易记错或弄混crontab的表达式,这时我们可以借助工具来进行验证。

在线工具:https://tool.lu/crontab/

如每隔12小时执行一次任务:

0 */12 * * *

接下来7次的执行时间:

2020-10-14 12:00:00
2020-10-15 00:00:00
2020-10-15 12:00:00
2020-10-16 00:00:00
2020-10-16 12:00:00
2020-10-17 00:00:00
2020-10-17 12:00:00   

添加cron任务

crontab -e

使用此命令会直接打开/var/spool/cron/下与用户名相同的文件,如是root,就相当于

vim /var/spool/cron/root

添加cron任务,编辑内容,按i插入(其实就是使用vi来操作文本)。

0-59/2 * * * * ls /home > home.log

:wq保存。

等同于下面这个命令

echo "*/2 * * * * ls /home > home.log" >> /var/spool/cron/root

添加完crontab任务后,可使用下面命令查看任务是否添加成功

crontab -l

重启crond生效

systemctl restart crond

查看服务运行情况

systemctl status crond

等了一分钟,发现任务没有运行,我以为home.log会出现在/var/spool/cron目录下

查看下cron的运行情况

cat /var/log/cron

tail -fn100 /var/log/cron

/var/log/cron记录了所有cron的运行记录

查看信息如下

Oct 14 10:38:01 mail CROND[25295]: (root) CMD (ls /home > home.log)
You have new mail in /var/spool/mail/root

修改crontab任务

crontab -e # 打开/var/spool/cron/root 文件

# 编辑
0-59/2 * * * * ls /home > /var/log/home.log

crontab -l # 查看

systemctl restart crond # 重启定时任务管理器,立即生效

观察cron记录,tail -fn100 /var/log/cron,发现执行

Oct 14 10:46:55 mail crond[29898]: (CRON) INFO (running with inotify support)
Oct 14 10:46:55 mail crond[29898]: (CRON) INFO (@reboot jobs will be run at computer's startup.)
Oct 14 10:47:01 mail CROND[29956]: (root) CMD (/usr/bin/ls /home > /var/log/home.log)

再查看日志,果然已经有了内容

cat /var/log/home.log

其他cron实例参考

意思是每两个小时重启一次apache

0 */2 * * * /sbin/service httpd restart 

每天22:50关闭ssh服务

50 22 * * * /sbin/service sshd stop  

每天7:50开启ssh服务

50 7 * * * /sbin/service sshd start

每月1号和15号检查/home 磁盘

0 0 1,15 * * /usr/sbin/fsck /home  

每小时的第一分执行 /home/bruce/backup这个文件

1 * * * * /home/bruce/backup  

每周一至周五3点钟,在目录/home中,查找文件名为*.xxx的文件,并删除4天前的文件。

00 03 * * 1-5 find /home "*.log" -mtime +4 -exec rm {} \;  

每月的1、11、21、31日是的6:30执行一次ls命令

30 6 */10 * * ls  

FAQ

如果我们使用 crontab 来定时执行脚本,无法执行,但是如果直接通过命令(如:./test.sh)又可以正常执行,这主要是因为无法读取环境变量的原因。

解决方法:

1、所有命令需要写成绝对路径形式,如:

/usr/local/bin/docker。

2、在 shell 脚本开头使用以下代码:

#!/bin/bash

source  /etc/profile
source  ~/.bash_profile

3、在 /etc/crontab 中添加环境变量,在可执行命令之前添加命令

. /etc/profile;/bin/sh

使得环境变量生效,例如:

20 03 * * * . /etc/profile;/bin/sh /var/www/runoob/test.sh

注意事项

1、新创建的 cron 任务,不会马上执行,至少要过 2 分钟后才可以,当然你可以重启 cron 来马上执行。

2、当crontab突然失效时,可以尝试/etc/init.d/crond restart解决问题。或者查看日志看某个job有没有执行/报错tail -f /var/log/cron。

3、千万别乱运行crontab -r。它从Crontab目录(/var/spool/cron)中删除用户的Crontab文件。删除了该用户的所有crontab都没了。

4、在crontab中%是有特殊含义的,表示换行的意思。如果要用的话必须进行转义%,如经常用的date ‘+%Y%m%d’在crontab里是不会执行的,应该换成date ‘+%Y%m%d’。