这是有关使用cron和crontab 的规范问题。
您被引导到这里是因为社区相当确定可以在下面找到问题的答案。如果下面没有回答您的问题,那么答案将帮助您收集有助于社区帮助您的信息。此信息应编辑为您的原始问题。
答案为“ 为什么我的crontab无法正常工作,如何解决它?可以在下面看到。这cron
用crontab突出显示了系统。
这是有关使用cron和crontab 的规范问题。
您被引导到这里是因为社区相当确定可以在下面找到问题的答案。如果下面没有回答您的问题,那么答案将帮助您收集有助于社区帮助您的信息。此信息应编辑为您的原始问题。
答案为“ 为什么我的crontab无法正常工作,如何解决它?可以在下面看到。这cron
用crontab突出显示了系统。
Answers:
这是社区Wiki,如果您发现此答案有任何错误或有其他信息,请对其进行编辑。
系统上的每个用户都可以拥有自己的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文件crontab -e
并保存时,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环境变量,例如
MAILTO=user@somehost.tld
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=/usr:/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将开始出现异常行为,并显示出奇怪的错误,有时可以正常工作,有时无法正常工作。当时间从下面改变时,这是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")"
... /path/to/your/command >/tmp/mycommand.log 2>&1
sudo apt-get install postfix
Debian Linux及其衍生版本(Ubuntu,Mint等)具有一些特性,可能会阻止您的cron作业执行;特别是,该文件/etc/cron.d
,/etc/cron.{hourly,daily,weekly,monthly}
必须:
最后一个会伤害经常毫无戒心的用户;特别是在这些文件夹命名之一任何脚本whatever.sh
,mycron.py
,testfile.pl
等会不会被执行,直到永远。
根据我的经验,到目前为止,这一点一直是对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)
sudo -u root passwd
Cron一切都被认为是非常基本的调度程序,并且语法不容易允许管理员制定稍微不常见的调度程序。
考虑以下工作,通常将其解释为“ command
每5分钟运行一次”:
*/5 * * * * /path/to/your/command
与:
*/7 * * * * /path/to/your/command
这 并不总是跑command
每7分钟。
请记住,/角色可以用来引入一个步骤,但是这些步骤不会超出系列的结尾,例如*/7
,从分钟开始每7分钟匹配一次,0-59
即0,7,14,21,28,35,42,49, 56,但一小时,下一之间会有批次之间有4分钟后, 00:56
一系列新的开始 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,当先前的运行尚未完成时,它将正常地失败,但否则将运行。请参阅以下问答:
* * * * * /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
一个不同但类似的问题是将批处理安排在每个月的第一个星期一(或第二个星期三)运行,等等。只需将批处理安排在每个星期一运行,然后在日期不在1 号或7 号到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发送错误。@请参阅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
for 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
将包含environment
“ root cron用户” 的清单。知道之后,相应地调整您的crontab
输入。
crontab
输入中指定所需的时间表:的时间表条目crontab
当然是在中定义的man crontab
,您应该阅读此内容。但是,阅读man crontab
和理解时间表是两件事。日程安排规范中的反复试验会变得非常乏味。幸运的是,有一个资源可以提供帮助:crontab专家。。输入您的时间表规格,它将以纯英语解释时间表。
最后,不要冒着被限制为一个crontab
条目的风险,因为您要安排一项工作,因此不要被此处的其他答案之一所困扰。您可以随意使用任意多个crontab
条目来获取所需的时间表。