「crontab」- 周期任务的配置文件 @20210419
配置文件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,9和0-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 文章内容调整