「crontab」- 周期任务的配置文件

  CREATED BY JENKINSBOT

配置文件crontab中描述了需要命令cron周期执行的任务。

配置文件的位置

系统级别的配置文件为/etc/crontab。通常由系统管理员编辑,执行系统维护相关的周期任务。

用户级别的配置文件位于/var/spool/cron/crontabs/中。每个用户在该目录中都有自己的crontab文件,单独存放。使用命令crontab(1)进行编辑。这其中任何给定的crontab中的命令都将使用拥有crontab文件的用户身份来执行。

文件内容概述

文件crontab中包含了cron(8)守护程序的指令,一般形式为:“此日期此时运行此命令”。

Uucp和News通常都有自己的crontabs,因此无需显式运行su(1)作为cron命令的一部分。

配置文件的内容分为第三部分:

  • 注释行;
  • 环境变量设置;
  • 周期任务指定;

下面将分别介绍这三部分。

配置中使用注释

空白行会被忽略;前导的空格和TAB也会被忽略;以井号(#)开始的行会被忽略。

注意事项
注释不允许和命令在同一行。就是说一行条目,要么是命令,要么是注释。下面的格式是不正确的:

	09,39 *     * * *     root   date >> /var/log/date # comment...

同样的,注释也不能和环境变量设置在同一行。

配置文件中的环境变量

文件crontab中可以指定命令执行的环境变量。

文件crontab从上到下进行解析,因此任何环境变量设置都只会影响文件中它们下面的cron命令。环境变量设置的形式:

	name = value

等号(=)周围的空格是可选的,value中任何后续的非前导空格都是分配给name的值的一部分。value字符串可以放在引号中(单引号或双引号,但要成对出现)以保留前导或尾随空白。要定义空变量,必须使用引号。对于环境替换、变量替换都不会进行不解析,因此类似:

	PATH = $HOME/bin:$PATH

的行不会按照你的期望进行解析。下面的这些也不会奏效:

A=1
B=2
C=$A $B

在最后一个值C中,不会替换定义的变量,因此C就是字面上的“$A $B”。

设置命令路径PATH的另一种方法是:即许多shell会将代字号(~)视为$HOME的代替,因此如果您将BASH用于任务,则可以使用:

SHELL=/bin/bash
PATH=~/bin:/usr/bin/:/bin

守护进程cron(8)自动设置了几个环境变量。SHELL设置为/bin/sh;LOGNAME和HOME是从文件crontab的所有者的/etc/passwd行设置的。PATH设置为“/usr/bin:/bin”。HOME、SHELL、PATH可能会被crontab文件中的设置覆盖;LOGNAME是作业运行的用户,可能不会更改。

另一个注意事项:LOGNAME变量有时在BSD系统上称为USER ……在这些系统上,也会设置USER。

除了LOGNAME、HOME、SHELL之外,如果由于在“当前”的crontab文件中运行命令而有任何理由发送邮件,则cron(8)将查找MAILTO。如果定义了MAILTO(并且非空),则将邮件发送给如此命名的用户。MAILTO还可用于通过用使用“逗号分隔收件人用户”的形式来将邮件发送到多个收件人。如果MAILTO已定义但为空(MAILTO=””),则不会发送任何邮件。否则,邮件将发送给crontab的所有者。

在Debian GNU/Linux系统上,cron支持pam_env模块,并加载/etc/environment和/etc/security/pam_env.conf指定的环境。它还从/etc/default/locale读取区域设置信息。但是,PAM设置不会覆盖上述设置,也不会覆盖crontab文件本身的任何设置。请特别注意,如果您想要“/usr/bin:/bin”以外的PATH,则需要在crontab文件中进行设置。

邮件发送

默认情况下,cron将使用“text/plain”的邮件“Content-Type:”标题发送邮件,并将“charset=”参数设置为启动crond(8)的语言环境的charmap/codeset(即默认系统区域设置),如果未设置LC_*环境变量,或LC_ *环境变量指定的区域设置(请参阅locale(7))。通过设置crontabs中的CONTENT_TYPE和CONTENT_TRANSFER_ENCODING变量来纠正邮件头的值,以此来对邮寄的cron作业输出使用不同的字符编码。

周期任务的定义指令

命令cron的格式非常符合V7标准,具有许多向上兼容的扩展。每行有五个时间日期字段,后跟一个命令,后跟一个换行符(’\n’)。系统crontab(/etc/crontab)使用相同的格式,除了在时间日期字段之后以及命令之前有一个指定执行命令的用户。因此由以下两种形式:

* * * * * command
* * * * * username command

字段之间可以使用空格(SPACE)或者制表符(TAB)进行分隔。

命令command允许的最大长度为998个字符。

当分钟、小时、月份字段与当前时间匹配时,以及当两个“天字段”(月中某天、星期几)中的至少一个与当前时间匹配时,命令由cron(8)执行(参阅下面的“注意事项”部分)。cron(8)每分钟检查一次cron条目。时间和日期字段是:

field          		allowed values
-----          		--------------
minute         		0-59
hour           		0-23
day of month   		1-31
month          		1-12 (or names, see below)
day of week    		0-7 (0 or 7 is Sun, or use names)

字段可以是星号(*),它总是代表“first-last”(从开始到最后)。

允许使用「数字范围」。「数字范围」是用连字符(-)分隔的两个数字。指定的范围包括在内。例如,“hour”条目的“8-11”表示在8,9,10,11小时执行。

允许使用「列表」。「列表」是由逗号分隔的一组数字(或数字范围)。例如1,2,5,90-4,8-12这两种。

「范围」可与「步长」结合使用。在「范围」之后跟有“/<number>”表示在该范围内跳过数字的值。例如,可以在小时字段中使用“0-23/2”来指定每隔一小时执行一次命令(V7标准中的替代方法是“0,2,4,6,8,10,12,14,16,18,20,22)。星号后也允许使用步长,所以如果你想说“每两个小时“,只需使用“*/2”。

“日期名称”也可用于“月份”和“星期几”字段。“日期名称”是指特定日期或月份的前三个字母(大小写无关紧要)。“日期名称”不允许使用范围或列表。

第“六”字段(行的其余部分)指定要运行的命令。该行的整个命令部分,直到换行符(LF)或百分号(%)字符,将由/bin/sh或crontab文件的SHELL变量中指定的Shell执行。除非使用反斜杠(\)进行转义,否则命令中的百分号(%)将更改为换行符,并且第一个%之后的所有数据将作为标准输入发送到命令。无法将单个命令行拆分为多行,例如Shell的尾部“\”是不行的。

注意:命令执行的日期可以由两个字段指定:月中的某天;星期几。如果两个字段都受到限制(即,不以*开头),则当任一字段与当前时间匹配时,将运行该命令。例如,“30 4 1,15 * 5”将导致命令在每个月的1号和15号凌晨4:30,以及每个星期五运行。但是,可以通过向命令添加测试(test)来实现所需的结果(请参阅下面的「配置示例」部分的最后一个示例)。

可能会出现以下八个特殊字符串中的一个,而不是前五个字段:

string         meaning
------         -------
@reboot        Run once, at startup.
@yearly        Run once a year, "0 0 1 1 *".
@annually      (same as @yearly)
@monthly       Run once a month, "0 0 1 * *".
@weekly        Run once a week, "0 0 * * 0".
@daily         Run once a day, "0 0 * * *".
@midnight      (same as @daily)
@hourly        Run once an hour, "0 * * * *".

请注意,就@reboot而言,启动是cron(8)守护进程启动的时刻。特别是,可能在某些系统守护程序或其他工具启动之前。这是由于机器的引导顺序。

注意事项

cron要求crontab中的每个条目以换行符(LF)结尾。如果crontab中的最后一个条目缺少换行符(即由EOF终止),则cron会认为crontab(至少部分地)已损坏。警告将写入syslog中。

存在的差异性

在指定星期几时,第0天和第7天都将被视为星期日。但是BSD和AT&T似乎对此持不同意见。

列表和范围允许在同一字段中共存。“1-3,7-9”的形式将被AT&T或BSD的cron拒绝(他们只支持“1-3”或“7,8,9”,不能)。

“日期范围”可以包括“步长”,因此“1-9/2”与“1,3,5,7,9”相同。

可以通过“日期名称”的形式指定一周中的几个月或几天。

可以在文件crontab中设置环境变量。在BSD或AT&T中,传递给子进程的环境基本上是来自/etc/rc的环境。

命令输出会邮件给crontab所有者(BSD无法执行此操作),可以邮寄给crontab所有者以外的人(SysV无法执行此操作),或者可以关闭该功能并且完全不会发送邮件(SysV也不能这样做)。

可以代替前五个字段出现的所有`@’命令都是扩展名。

存在的限制

守护程序cron以定义的时区运行。它目前不支持基于每个用户的时区设置。所有任务:系统和用户将根据配置的时区运行。即使用户在其crontab中指定了TZ环境变量,这也只会影响crontab中执行的命令,而不会影响crontab任务本身的执行。

POSIX指定:如果日期和星期字段其中任何一个为“*”,则日期和星期字段都需要与当前时间匹配。但是,此实现仅检查第一个字符是否为“*”。这就是“0 0 */2 * sun”每周日运行的原因,这是一个奇数日期,而POSIX标准将在每个星期日和每个奇数日期运行。

crontab语法无法定义可以想象的所有可能的时间段。例如,定义一个月的最后一个工作日并不简单。要在无法使用crontab语法定义的时间段内运行任务,最好的方法是让程序本身检查日期和时间信息,并仅在周期与所需周期匹配时继续执行。

如果程序本身无法进行检查,则需要包装脚本。可用于日期分析的有用工具是ncal或calendar。例如,要在每个月的最后一个星期六运行程序,您可以使用以下包装器代码:

	0 4 * * Sat   [ "$(date +\%e)" = "$(LANG=C ncal | sed -n 's/^Sa .* \([0-9]\+\) *$/\1/p')" ] && echo "Last Saturday" && program_to_run

复杂的需求通常需要与脚本配合才能实现。

配置示例

用户级配置文件示例

以下列出了用户crontab文件的示例:

# use /bin/bash to run commands, instead of the default /bin/sh
SHELL=/bin/bash

# mail any output to `paul', no matter whose crontab this is
MAILTO=paul

#
# run five minutes after midnight, every day
5 0 * * *       $HOME/bin/daily.job >> $HOME/tmp/out 2>&1

# run at 2:15pm on the first of every month -- output mailed to paul
15 14 1 * *     $HOME/bin/monthly

# run at 10 pm on weekdays, annoy Joe
0 22 * * 1-5    mail -s "It's 10pm" joe%Joe,%%Where are your kids?%
23 0-23/2 * * * echo "run 23 minutes after midn, 2am, 4am ..., everyday"
5 4 * * sun     echo "run at 5 after 4 every Sunday"
0 */4 1 * mon   echo "run every 4th hour on the 1st and on every Monday"
0 0 */2 * sun   echo "run at midn on every Sunday that's an uneven date"

# Run on every second Saturday of the month
0 4 8-14 * *    test $(date +\%u) -eq 6 && echo "2nd Saturday"

以上所有示例都运行非交互式程序。如果您希望运行与用户桌面交互的程序,则必须确保设置了正确的环境变量DISPLAY:

# Execute a program and run a notification every day at 10:00 am
0 10 * * *  $HOME/bin/program | DISPLAY=:0 notify-send "Program run" "$(cat)"

否则无法进行提示。

系统级配置文件示例

以下列出了常规系统范围的crontab文件的内容。与用户的crontab不同,此/etc/crontab文件具有用户名username字段:

# /etc/crontab: system-wide crontab
# Unlike any other crontab you don't have to run the `crontab'
# command to install the new version when you edit this file
# and files in /etc/cron.d. These files also have username fields,
# that none of the other crontabs do.

SHELL=/bin/sh
PATH=/usr/local/sbin:/usr/local/bin:/sbin:/bin:/usr/sbin:/usr/bin

# 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
# |  |  |  |  |
# m h dom mon dow user command
17 * * * *  root  cd / && run-parts --report /etc/cron.hourly
25 6 * * *  root  test -x /usr/sbin/anacron || ( cd / && run-parts --report /etc/cron.daily )
47 6 * * 7  root  test -x /usr/sbin/anacron || ( cd / && run-parts --report /etc/cron.weekly )
52 6 1 * *  root  test -x /usr/sbin/anacron || ( cd / && run-parts --report /etc/cron.monthly )

请注意,默认情况下,所有系统范围的任务都将从早上6点运行到早上7点。对于在此期间未启动的系统,除非更改上述默认值,否则仅执行每小时任务。

相关文档

cron(8), crontab(1)

参考文献

man 5 crontab, version 3.0pl1-130

更新日志

04/23/2018 创建文章
08/17/2018 文章内容调整