Skip to content

crontab 定时任务

Linux中,周期执行的任务一般由cron这个守护进程来处理 ps -ef | grep cron

cron 读取一个或多个配置文件,这些配置文件中包含了命令行及其调用时间。

cron 的配置文件称为 crontab,是 cron table的简写。

一、 cron在3个地方查找配置文件(设置shell脚本):

  • /var/spool/cron/ 这个目录下存放的是每个用户(包括root)的 crontab 任务,每个任务以创建者的名字命名,比如用户 tom 建的 crontab 任务对应的文件就是 /var/spool/cron/tom
Plaintext
sudo ls -l /var/spool/cron/(或有时是 /var/spool/cron/crontabs/)
-rw------- 1 root     crontab 1071 2011-09-19 17:20 root
-rw------- 1 duoli    crontab 1176 2011-09-24 11:07 duoli

一般一个用户最多只有一个crontab文件(如:root, duoli 等),其对应日志在 /var/spool/mail/root(或 /var/spool/mail/duoli)文件里

  • /etc/crontab 这个文件负责安排由系统管理员制定的维护系统以及其他任务的crontab。
Plaintext
SHELL=/bin/bash
PATH=/sbin:/bin:/usr/sbin:/usr/bin
MAILTO=root
HOME=/
# .---------------- 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
# |  |  |  |  |
# *  *  *  *  *  command to be executed

说明

可以进行快捷记忆 : 分时天月周

Plaintext
*/5 * * * * root /usr/libexec/atrun
minute:代表一小时内的第几分,范围 0-59。
hour:代表一天中的第几小时,范围 0-23。
mday:代表一个月中的第几天,范围 1-31。
month:代表一年中第几个月,范围 1-12。
wday:代表星期几,范围 0-7 (0及7都是星期天)。
who:要使用什么身份执行该指令,当您使用 crontab -e 时,不必加此字段。
command:所要执行的指令。
  • /etc/cron.d/ 这个目录用来存放任何要执行的crontab文件或脚本。

二、 权限

crontab 权限问题到 /var/adm/cron/ 下一看,文件 cron.allowcron.deny 是否存在用法如下:

  1. 如果两个文件都不存在,则只有 root 用户才能使用 crontab 命令。
  2. 如果 cron.allow 存在但 cron.deny 不存在,则只有列在 cron.allow 文件里的用户才能使用 crontab 命令,如果 root 用户也不在里面,则 root 用户也不能使用 crontab。
  3. 如果 cron.allow 不存在, cron.deny 存在,则只有列在 cron.deny 文件里面的用户不能使用 crontab 命令,其它用户都能使用。
  4. 如果两个文件都存在,则列在 cron.allow 文件中而且没有列在 cron.deny 中的用户可以使用 crontab,如果两个文件中都有同一个用户,以 cron.allow 文件里面是否有该用户为准,如果 cron.allow 中有该用户,则可以使用 crontab 命令。

AIX 中 普通用户默认都有 crontab 权限,如果要限制用户使用 crontab ,就需要编辑 /var/adm/cron/cron.deny

HP-UNIX 中默认普通用户没得 crontab 权限 ,要想放开普通用户的 crontab 权限可以编辑 /var/adm/cron/cron.allow

三、 创建cron脚本

第一步:写 cron 脚本文件,命名为 crontest.cron

Plaintext
15,30,45,59 * * * * echo "xgmtest....." >> xgmtest.txt

表示,每隔15分钟,执行打印一次命令

第二步:添加定时任务。执行命令 crontab crontest.cron。搞定

第三步:crontab -l 查看定时任务是否成功或者检测 /var/spool/cron下是否生成对应cron脚本

四、 cron 服务和日志

cron是一个linux下 的定时执行工具,可以在无需人工干预的情况下运行作业。

Plaintext
systemctl start crond    // 启动服务
systemctl stop crond     // 关闭服务
systemctl restart crond  // 重启服务
systemctl reload crond   // 重新载入配置
systemctl status crond   // 查看服务状态

CentOS 的 cron 日志默认位置在 /var/log/cron 中。这个文件仅记录命令的执行,而不记录结果或退出状态。默认情况下,已执行命令的输出进入用户的邮件。可以通过 crontab 内的
MAILTO 变量指定电子邮件地址。

你可能应该调整 logrotate 规则,因为它会删除 /var/log/secure
日志 链接

五、 crontab用法

crontab 命令用于安装、删除或者列出用于驱动 cron 后台进程的表格,用户把需要执行的命令序列放到crontab文件中以获得执行。

每个用户都可以有自己的crontab文件,/var/spool/cron 下的crontab文件不可以直接创建或者直接修改,该crontab文件是通过 crontab -e命令创建的

crontab 文件中,若需配置待执行的命令及其运行时间,需遵循特定格式:该文件内的每一行均包含六个字段(域)。其中,前五个字段用于指定命令的执行时间,最后一个字段则为需要执行的具体命令。

每个域之间使用空格或者制表符分隔。格式如下:

Plaintext
minute hour day-of-month month-of-year day-of-week commands

合法值 00-59 00-23 01-31 01-12 0-6 (0 is sunday)

除了数字外,还有几个特殊符号,分别是 _/-,。各符号的含义如下:

  • _:代表取值范围内的所有数字;
  • /: 表示“每”的含义,例如 /5 即代表“每5个单位”;
  • -:代表“从某个数字到另一个数字”的范围关系;
  • ,:用于分隔多个离散的数字。

另外有几个命令需要注意

  • l 在标准输出上显示当前的crontab。
  • r 删除当前的crontab文件。
  • e 使用 VISUAL 或者 EDITOR 环境变量所指的编辑器编辑当前的 crontab 文件。

当结束编辑离开时,编辑后的文件将自动安装。

几个例子

Plaintext
# 每天早上6点
0 6 * * * echo "Good morning." >> /tmp/test.txt //注意单纯echo,从屏幕上看不到任何输出,因为cron把任何输出都email到root的信箱了。

# 每两个小时
0 */2 * * * echo "Have a break now." >> /tmp/test.txt

# 晚上11点到早上8点之间每两个小时和早上八点
0 23-7/2,8 * * * echo "Have a good dream" >> /tmp/test.txt

# 每个月的4号和每个礼拜的礼拜一到礼拜三的早上11点
0 11 4 * 1-3 command line

# 1月1日早上4点
0 4 1 1 * command line SHELL=/bin/bash PATH=/sbin:/bin:/usr/sbin:/usr/bin MAILTO=root //如果出现错误,或者有数据输出,数据作为邮件发给这个帐号 HOME=/

# 每小时(第一分钟)执行/etc/cron.hourly内的脚本
01 * * * * root run-parts /etc/cron.hourly

# 每天(凌晨4:02)执行/etc/cron.daily内的脚本
02 4 * * * root run-parts /etc/cron.daily

# 每星期(周日凌晨4:22)执行/etc/cron.weekly内的脚本
22 4 * * 0 root run-parts /etc/cron.weekly

# 每月(1号凌晨4:42)去执行/etc/cron.monthly内的脚本
42 4 1 * * root run-parts /etc/cron.monthly

# 注意:  "run-parts"这个参数了,如果去掉这个参数的话,后面就可以写要运行的某个脚本名,而不是文件夹名。

# 每天的下午4点、5点、6点的5 min、15 min、25 min、35 min、45 min、55 min时执行命令。
5,15,25,35,45,55 16,17,18 * * * command

# 每周一,三,五的下午3:00系统进入维护状态,重新启动系统。
00 15 * *1,3,5 shutdown -r +5

# 每小时的10分,40分执行用户目录下的innd/bbslin这个指令:
10,40 * * * * innd/bbslink

# 每小时的1分执行用户目录下的bin/account这个指令:
1 * * * * bin/account

# 每天早晨三点二十分执行用户目录下如下所示的两个指令(每个指令以;分隔):
203 * * * (/bin/rm -f expire.ls logins.bad;bin/expire$#@62;expire.1st)

# 每年的一月和四月,4号到9号的3点12分和3点55分执行/bin/rm -f expire.1st这个指令,并把结果添加在mm.txt这个文件之后(mm.txt文件位于用户自己的目录位置)。
12,553 4-91,4 * /bin/rm -f expire.1st>>mm.txt

FAQ

crontab 编辑

输入编辑命令: crontab -e

Plaintext
# m h  dom mon dow   command
SHELL=/bin/bash
30 * * * * cd /home/barry/top800/top10/top10_fruits/ && ./top10_all.sh

Ctrl + O(写入) -> enter键(保存文件名) -> Ctrl + X(退出)

输入查看命令: crontab -l

Plaintext
# m h  dom mon dow   command
SHELL=/bin/bash
30 * * * * cd /home/barry/top800/top10/top10_fruits/ && ./top10_all.sh(建议使用此方式)

语法错误

Plaintext
Syntax error: "(" unexpected

参见: LINUX - BASH Syntax Error

或者,执行 crontab -e 时指定 Shell 解释器(sh):SHELL=/bin/bash(请参见上面的 crontab 编辑示例)。

若出现路径错误:例如在文件 /var/spool/crontab/duoli 中添加了相关命令后,在日志文件 /var/spool/mail/duoli 中提示无法找到 xxx.sh 的路径,即属于此类问题。

Plaintext
30 * * * *  /home/barry/top800/top10/top10_fruits/top10_all.sh
# 或
30 * * * * bash /home/barry/top800/top10/top10_fruits/top10_all.sh

是因为你在crontab中使用了绝对路径执行脚本 top10_all.sh,因此在脚本 top10_all.sh 中引用的其它脚本也都需要使用绝对路径,才能被crontab找到并执行

如何避免绝对路径复杂的设置呢,如上文几个问题 所示,采用如下格式:

Plaintext
30 * * * * cd /home/barry/top800/top10/top10_fruits/ && ./top10_all.sh
# (建议使用此方式,先进入该目录,然后在执行脚本;否则,执行脚本中的其它脚本都需要加绝对路径)

输出执行日志

在命令末尾添加 2>&1, 这会将 stderr 输出重定向到标准输出。然后再确认你正在记录 crontab 的日志

Plaintext
0 0,12 1 */2 * ( /sbin/ping -c 1 192.168.0.1; ls -la ) >>/var/log/cronrun 2>&1

假如命令行中包含 %

在使用 date 的时候常常会用到 % 来格式化日期, 但是在 crontab 中, % 是一个特殊字符, 需要进行转移

%(百分号)在 crontab 中是一个特殊字符,相当于回车,如果在命令(command)字段中包含 %,那么只有第一个百分号前的文本才会包含在实际命令中,之后的内容将作为标准输入赋值给前面的命令。如果命令行中需要 %,必须得在 %前面加一个反斜线""来转义,即“%”, 如

在 Linux 系统中执行 man 5 crontab 就可以找到如下描述

Plaintext
The  "sixth"  field  (the rest of the line) specifies the command to be
run.  The entire command portion of the line, up  to  a  newline  or  %
character, will be executed by /bin/sh or by the shell specified in the
SHELL variable of the cronfile.   Percent-signs  (%)  in  the  command,
unless escaped with backslash (\\), will be changed into newline charac-
ters, and all data after the first % will be sent  to  the  command  as
standard input.

第六个域(行的剩余部分)指明了要运行的命令。一行中整个命令部分遇到一个换行符或%结束,命
令会以/bin/sh执行或以cron文件中 SHELL变量指明的shell执行。命令中的百分号(%) ,除
非以反斜线 “\\” 转义,否则会被转换为换行符,第一个%后的所有数据会被发送给命令作为标准输入

如果你的命令行中存在 %, 请记得加上 \\进行转义

按秒来执行计划任务

Plaintext
* * * * * sleep 9 &&  /home/somedir/scripts.sh
* * * * * sleep 12 &&  /home/somedir/scripts.sh
* * * * * sleep 15 &&  /home/somedir/scripts.sh

参考文章