这是关于使用cron和crontab的 规范问题 。
您被引导到这里是因为社区相当确定可以在下面找到问题的答案。如果下面没有回答您的问题,那么答案将帮助您收集有助于社区帮助您的信息。此信息应编辑为您的原始问题。
答案为(为什么我的crontab不起作用,如何解决它?)。这解决了cron
系统并突出显示了crontab。
这是 社区Wiki ,如果您发现此答案有误或有其他信息,请进行编辑。
系统上的每个用户都可以拥有自己的crontab文件。根crontab文件和用户crontab文件的位置取决于系统,但它们通常在/var/spool/cron
以下。
有一个系统范围的/etc/crontab
文件,/etc/cron.d
目录可能包含crontab片段,这些片段也由cron读取和操作。某些Linux发行版(例如Red Hat)也具有/etc/cron.{hourly,daily,weekly,monthly}
,它们是目录,脚本,该脚本将以root用户权限每小时/每天/每周/每月执行一次。
root可以始终使用crontab命令;普通用户可能会或可能不会被授予访问权限。当您使用命令crontab -e
编辑crontab文件并保存时,crond会检查该文件的基本有效性,但不能保证您的crontab文件格式正确。有一个名为cron.deny
的文件,它将指定哪些用户不能使用cron。 cron.deny
文件的位置取决于系统,可以删除,这将允许所有用户使用cron。
如果计算机未开机或crond守护程序未运行,并且运行命令的日期/时间已过,则crond将不会赶上并运行过去的查询。
Crontab命令用单行表示。您不能使用\
将命令扩展为多行。井号(#
)表示注释,这意味着cron会忽略该行上的任何内容。前导空格和空白行将被忽略。
在命令中使用百分号(%
)时要非常小心。除非它们已转义\%
,否则它们将转换为换行符,并且第一个未转义的%
之后的所有内容都将传递到stdin上的命令中。
Crontab文件有两种格式:
用户crontab
# 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)
# | | | | |
# * * * * * command to be executed
系统范围内的/etc/crontab
和/etc/cron.d
片段
# 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)
# | | | | |
# * * * * * user-name command to be executed
注意,后者需要一个用户名。该命令将以指定的用户身份运行。
该行的前5个字段表示应运行命令的时间。您可以在时间规范中使用数字或适当的日期/月份名称。
,
)用于指定列表,例如1,4,6,8,表示以1,4,6,8运行。-
)指定,并且可以与列表(例如1-3,9-12表示介于1和3之间,然后介于9和12之间。/
字符可用于引入步骤,例如2/5表示从2开始,然后每5(2,7,12,17,22 ...)。他们没有结束。*
)表示该字段的整个范围(例如,分钟字段为0-59
)。*/2
表示从相关字段的最小值开始,然后每2例如0代表分钟(0,2 ... 58),1代表月(1,3 ... 11)等.默认情况下,cron会将命令的任何输出邮寄给运行命令的用户。如果没有输出,将没有邮件。如果您希望cron将邮件发送到其他帐户,则可以在crontab文件中设置MAILTO环境变量,例如.
[email protected]
1 2 * * * /path/to/your/command
您可以将stdout和stderr重定向到文件。捕获输出的确切语法可能会有所不同,具体取决于所使用的Shell cron。以下是两个将所有输出保存到/tmp/mycommand.log
的文件的示例:
1 2 * * * /path/to/your/command &>/tmp/mycommand.log
1 2 * * * /path/to/your/command >/tmp/mycommand.log 2>&1
Cron通过syslog记录其操作,该操作通常取决于/var/log/cron
或/var/log/syslog
。
如果需要,您可以使用以下代码过滤cron语句:.
grep CRON /var/log/syslog
现在,我们已经了解了cron的基础知识,文件的位置以及如何使用它们,让我们看一些常见的问题。
如果cron没有运行,那么您的命令将不会被调度...
ps -ef | grep cron | grep -v grep
应该给你像
root 1224 1 0 Nov16 ? 00:00:03 cron
要么
root 2018 1 0 Nov14 ? 00:00:06 crond
如果不重启
/sbin/service cron start
要么
/sbin/service crond start
可能还有其他方法。使用您的发行版提供的内容。
可用的环境变量可能非常有限。通常,您只会定义一些变量,例如$LOGNAME
,$HOME
和$PATH
。
特别要注意的是PATH
被限制为/bin:/usr/bin
。 绝大多数“我的cron脚本不起作用”问题是由这种限制性路径引起的。如果您的命令位于其他位置,则可以通过以下两种方法解决此问题:
提供命令的完整路径。
1 2 * * * /path/to/your/command
在crontab文件中提供合适的PATH
PATH=/bin:/usr/bin:/path/to/something/else
1 2 * * * command
如果您的命令需要其他环境变量,则也可以在crontab文件中定义它们。
无论您执行的程序在文件系统上的哪个位置,在cron运行时,程序的当前工作目录均为用户的主目录。如果您访问程序中的文件,则在使用相对路径时必须考虑到这一点,或者(最好)在任何地方都使用完全限定的路径,这样可以避免所有人的混乱。
Cron通常要求命令以新行终止。编辑您的crontab;转到包含最后一个命令的行的末尾并插入新行(按Enter键)。
您不能将用户crontab格式的crontab用于/ etc/crontab或/etc/cron.d中的片段,反之亦然。用户格式化的crontab在行的第6位不包含用户名,而系统格式化的crontab包括用户名并以该用户身份运行命令。
#!/bin/sh
放在顶部)如果您的日期最近是由用户或系统更新,时区或其他时间更改的,则crontab将开始出现异常行为,并显示异常的bug,有时可以正常工作,有时不能正常工作。当时间从下面改变时,这是crontab尝试尝试“做您想做的事”的尝试。更改小时后,“分钟”字段将失效。在这种情况下,仅星号将被接受。重新启动cron并重试一次,而无需连接到互联网(因此日期没有机会重置为时间服务器之一)。
为了强调有关百分号的建议,下面是cron如何处理百分号的示例:
# cron entry
* * * * * cat >$HOME/cron.out%foo%bar%baz
将创建包含3行的〜/ cron.out文件
foo
bar
baz
当使用date
命令时,这特别麻烦。确保逃脱百分号
* * * * * /path/to/command --day "$(date "+\%Y\%m\%d")"
Debian Linux及其衍生版本(Ubuntu,Mint等)具有某些特性,可能会阻止您的cron作业执行;尤其是/etc/cron.d
,/etc/cron.{hourly,daily,weekly,monthly}
中的文件必须:
最后一个会伤害经常毫无戒心的用户;特别是这些文件夹之一中名为whatever.sh
,mycron.py
,testfile.pl
等的任何脚本,将永远执行not。
以我的经验,到目前为止,这一点一直是对Debian及其衍生工具不执行cronjob的最常见原因。
如有必要,请参见man cron
了解更多详细信息。
如果您的cronjobs停止工作,请检查您的密码是否尚未过期。因为一旦激活,所有cron作业都会停止。
在/var/log/messages
类似于以下显示用户身份验证问题的代码:
(username) FAILED to authorize user with PAM (Authentication token is no longer valid; new one required)
Cron一切都被认为是非常基本的调度程序,并且语法不容易允许管理员制定稍微不常见的调度程序。
考虑以下工作,通常将其解释为“每5分钟运行command
”:
_*/5 * * * * /path/to/your/command
_
与:
_*/7 * * * * /path/to/your/command
_
其中不会总是每7分钟运行command
次。
请记住 / 字符可以用来介绍一个步骤,但是这些步骤不会超出系列的结尾,例如_*/7
_与分钟数_0-59
_相匹配,即每7分钟匹配一次,即0,7,14,21,28,35,42,49,56但在一个小时到下一个之间在_00:56
_之后,将有每批之间只有4分钟,一个新的系列将从_01:00
_,_01:07
_等开始(并且批处理不会在_01:03
_,_01:10
_,_01:17
_等)。
创建多个批次
而不是单个cron作业,而是创建多个批处理,这些批处理将结果组合成所需的计划。
例如,每40分钟(00:00、00:40、01:20、02:00等)运行一批,创建两个批次,一个在偶数小时运行两次,第二个仅在奇数小时运行:
_# The following lines create a batch that runs every 40 minutes i.e.
# runs on 0:00, 0:40, 02:00, 02:40 04:00 etc to 22:40
0,40 */2 * * * /path/to/your/command
# runs on 01:20, 03:20, etc to 23:20
20 1/2 * * * /path/to/your/command
# Combined: 0:00, 0:40, 01:20, 02:00, 02:40, 03:20, 04:00 etc.
_
减少批次运行频率
而不是每7分钟运行一次批处理(这很难将其分解为多个批处理),而是每10分钟运行一次。
更频繁地启动批处理(但要防止多个批处理并发运行)
由于批处理运行时间会增加/波动,因此会生成许多奇怪的时间表,然后以一些额外的安全余量来调度批处理,以防止同一批批处理的后续运行重叠并发运行。
相反,请换个思路,创建一个cronjob,当先前的运行尚未完成时,它将正常地失败,但否则将运行。看到这个 Q&A :
_* * * * * /usr/bin/flock -n /tmp/fcj.lockfile /usr/local/bin/frequent_cron_job
_
一旦先前的/ usr/local/bin/frequent_cron_job运行完成,几乎可以立即开始新运行。
更频繁地开始批量处理(但在条件不正确时可以正常退出)
由于cron语法受到限制,因此您可以决定在批处理作业本身中放置更复杂的条件和逻辑(或在现有批处理作业周围的包装脚本中)。这样一来,您就可以利用自己喜欢的脚本语言的高级功能来注释您的代码,并且可以防止crontab条目本身难以理解的构造。
在bash中,_seven-minute-job
_看起来像这样:
_#!/bin/bash
# seven-minute-job
# This batch will only run when 420 seconds (7 min) have passed
# since the file /tmp/lastrun was either created or updated
if [ ! -f /tmp/lastrun ] ; then
touch /tmp/lastrun
fi
if [ $(( $(date +%s) - $(date -r /tmp/lastrun +%s) )) -lt 420 ] ; then
# The minimum interval of 7 minutes between successive batches hasn't passed yet.
exit 0
fi
#### Start running your actual batch job below
/path/to/your/command
#### actual batch job is done, now update the time stamp
date > /tmp/lastrun
#EOF
_
然后您可以安全地(尝试)每分钟运行一次:
_* * * * * /path/to/your/seven-minute-job
_
一个不同但又类似的问题是将批处理安排在每个月的第一个星期一(或第二个星期三)运行,等等。简单地将批处理安排在每个星期一运行,并且当日期不在两者之间时退出st 或7日 并且星期几不是星期一。
_#!/bin/bash
# first-monday-of-the-month-Housekeeping-job
# exit if today is not a Monday (and prevent locale issues by using the day number)
if [ $(date +%u) != 1 ] ; then
exit 0
fi
# exit if today is not the first Monday
if [ $(date +%d) -gt 7 ] ; then
exit 0
fi
#### Start running your actual batch job below
/path/to/your/command
#EOF
_
然后您可以安全地(尝试)在每个星期一运行:
_0 0 * * 1 /path/to/your/first-monday-of-the-month-Housekeeping-job
_
不要使用cron
如果您的需求很复杂,则可以考虑使用更高级的产品,该产品旨在运行复杂的计划(分布在多个服务器上),并支持触发器,作业依赖性,错误处理,重试和重试监视等。行业术语是“企业” “ 作业计划 和/或“工作量自动化”。
如果您有一些cron工作,例如:
php /bla/bla/something.php >> /var/logs/somelog-for-stdout.log
而且如果发生错误,则会将它们发送给您,但不会-请检查一下。
默认情况下,PHP不向STDOUT发送错误。 @see https://bugs.php.net/bug.php?id=22839
要解决此问题,请在cli的php.ini中或您的行中(或在您的PHP bash包装器中)添加以下内容:
第一个设置将使您具有“ Memory oops”之类的致命危险,而第二个则将它们全部重定向到STDERR。只有在您可以睡个好觉之后,所有内容才会发送到您根的邮件中,而不仅仅是被记录下来。
添加我的答案 从这里开始 以获得完整性,并添加另一个可能有用的资源:
cron
用户与您拥有不同的$PATH
:用户使用crontab
条目经常遇到的一个问题是,他们忘记了cron
在与登录用户不同的environment
中运行。例如,用户在其$HOME
目录中创建程序或脚本,然后输入以下命令来运行它:
$ ./certbot ...
该命令可以从他的命令行完美运行。然后,用户将该命令添加到其crontab
中,但发现此命令不起作用:
*/10 * * * * ./certbot ....
在这种情况下失败的原因是,cron
用户的./
是不同于登录用户的位置。也就是说,environment
是不同的! PATH是environment
的一部分,通常对于cron
用户而言是不同的。使这个问题复杂化的是,对于所有 * nix 发行版,environment
的cron
都不相同,并且有 cron
的多个版本
解决此特定问题的简单方法是在cron
条目中为crontab
用户提供完整的路径规范:
0 22 * * * /path/to/certbot .....
cron
用户的environment
是什么?在某些情况下,我们可能需要了解系统上environment
的完整cron
规范(否则我们可能会感到好奇)。 environment
用户的cron
是什么,它与我们的用户有什么区别?此外,我们可能需要知道另一个environment
用户的cron
-例如root
。 root
用户的environment
使用cron
?一种学习方法是让cron
告诉我们:
~/
)中创建Shell脚本:$ nano ~/envtst.sh
#!/bin/sh
/bin/echo "env report follows for user "$USER >> /home/you/envtst.sh.out
/usr/bin/env >> /home/you/envtst.sh.out
/bin/echo "env report for user "$USER" concluded" >> /home/you/envtst.sh.out
/bin/echo " " >> /home/you/envtst.sh.out
$ chmod a+rx ~/envtst.sh
/home/you/envtst.sh.out
中的输出。此输出将以您登录为$USER
的身份显示当前环境:$ ./envtst.sh $$ cat /home/you/envtst.sh.out
crontab
进行编辑:$ crontab -e -u root
crontab
的底部输入以下行:* * * * * /home/you/envtst.sh >> /home/you/envtst.sh.err 2>&1
答案:输出文件/home/you/envtst.sh.out
将包含“ root cron用户”的environment
的列表。知道这一点后,请相应地调整crontab
条目。
crontab
条目中指定所需的时间表:crontab
的计划条目当然是在man crontab
中定义的,您应该阅读此内容。但是,阅读man crontab
和了解进度表是两件事。进度表规范上的反复试验可能会变得很繁琐非常。幸运的是,有一个资源可以提供帮助: crontab专家。 。输入您的时间表规范,它将以纯英语解释时间表。
最后,不要冒着被限制为单个crontab
条目的风险,因为这里有一项要安排的工作,因此有可能被此处的其他答案之一所困扰。您可以随意使用任意数量的crontab
条目来获取所需的时间表。