介绍

通过crontab 命令,我们可以在固定的间隔时间执行指定的系统指令或 shell script脚本。时间间隔的单位可以是分钟、小时、日、月、周及以上的任意组合。这个命令非常适合周期性的日志分析或数据备份等工作。
关于crontab的用途很多,如:

  • 定时系统检测;
  • 定时数据采集;
  • 定时日志备份;
  • 定时更新数据缓存;
  • 定时生成报表;
  • 其他一些定时任务

    格式

    默认从左到右为:”秒 分 小时 日 月 星期几 年份”。

  • 第1列分钟0~59

  • 第2列小时0~23(0表示子夜)
  • 第3列日1~31
  • 第4列月1~12
  • 第5列星期0~7(0和7表示星期天)
  • 第6列要运行的命令

Crontab - 图1
image.png
image.png

实例

  1. * * * * * echo "hello" #每1分钟执行hello
  2. 3,15 * * * * myCommand #每小时第三分钟和第十五分钟执行
  3. 3,15 8-11 * * * myCommand# 在上午8点到11点的第3和第15分钟执行
  4. 3,15 8-11 */2 * * myCommand #每隔两天的上午8点到11点的第3和第15分钟执行
  5. 30 21 * * * /etc/init.d/smb restart #每晚的21:30重启smb
  6. 0 23 * * 6 /etc/init.d/smb restart #每星期六的晚上11 : 00 pm重启smb
// 从左往右: 秒 分 时 日 月 星期 年

"30 * * * * ? *"  // 表示半分钟触发一次事件
"0 0 12 ? * WED"  // 表示每个星期三中午12点
"0 0,15 8-11 * * 2" // 每周一上午8点至11点(8,9,10,11)的第0和第15分钟都触发一次事件
"0 0/5 15 * * ?" // 在每天下午3点到下午3:55期间的每5分钟触发
"0 0 12 L * ?" // 每月最后一日的中午12:00触发事件
"0 0 12 4W * ?" // 每月距离4号最近的工作日的中午12:00触发事件
"0 0 12 LW * ?" // 每月最后一个工作日的中午12:00触发事件 
"0 0 12 ? * 6#3" // 每月第3个星期五中午12:00触发事件 
"0 11 11 11 11 ? 2019" // 2019年的11月11号 11点11分触发(光棍节)

注意事项

新创建的cron job,不会马上执行,至少要过2分钟才执行。如果重启cron则马上执行。
当crontab失效时,可以尝试/etc/init.d/crond restart解决问题。或者查看日志看某个job有没有执行/报错tail -f /var/log/cron。

$service cron restart

使用有坑

crontab使用中常会遇到各种坑。如:

环境变量问题

当我们刚使用crontab时,有人会告知所有命令尽量都使用绝对路径,以防错误。为什么?这就和我们下面要谈的环境变量有关了。
首先,获取控制台环境变量看下

$ env
XDG_SESSION_ID=10
HOSTNAME=localhost.localdomain
SHELL=/bin/bash
PERL_MB_OPT=--install_base /root/perl5
USER=root
MAIL=/var/spool/mail/root
PATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/usr/local/php5/bin
PWD=/var/mail
SHLVL=1
HOME=/root
LOGNAME=root
XDG_RUNTIME_DIR=/run/user/0
_=/usr/bin/env

考虑篇幅,输出有删减。
然后,获取crontab环境变量信息

* * * * * /usr/bin/env > /tmp/env.txt

输出结果,如下

$ cat /tmp/env.txt
XDG_SESSION_ID=732
SHELL=/bin/sh
USER=root
PATH=/usr/bin:/bin
PWD=/root
LANG=de_DE.UTF-8
SHLVL=1
HOME=/root
LOGNAME=root
XDG_RUNTIME_DIR=/run/user/0
_=/usr/bin/en

对比分析两者输出
对比crontab与控制台输出,我们发现两者的环境变量差异很大。如果命令在控制台执行成功,而在crontab执行失败,我们需要考虑是否命令涉及的环境变量在crontab和控制台间存在差异。
明白crontab使用绝对路径执行命令原因了吗?
我们知道命令默认查找路径是由PATH指定的。
从上面输出结果可知,控制台的PATH值为

PATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/usr/local/php/bin

crontab的PATH值为

PATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/usr/local/php/bin

crontab的PATH值为

PATH=/usr/bin:/bin

/usr/local/php/bin/下面存在php命令,在控制台执行成功

$ php index.php

因在crontab的PATH变量无/usr/local/php/bin/,其执行php命令则会失败。

解决方式

已知哪个环境变量导致问题,可以直接在crontab配置中加入变量配置。
不知哪个环境变量导致问题,终极大招是引入控制台环境变量,如下

* * * * * source /$HOME/.bash_profile && command

当然,对于某特定环境变量或有特定的处理方式,如PATH,命令使用绝对路径亦可解决。