为什么我的crontab无法正常工作,我该如何排除故障?

这是关于使用cron&crontab的规范问题 。

你已经被引导到这里,因为社区相当确定你的问题的答案可以在下面find。 如果您的问题未在下面得到解答,那么答案将有助于您收集有助于社区帮助您的信息。 这个信息应该被编辑成你原来的问题。

为什么我的crontab无法正常工作,我该如何排除故障? '可以在下面看到。 这就解决了crontab高亮显示的cron系统。

如何解决所有的crontab相关的问题(Linux)


这是一个社区wiki ,如果你发现这个答案有任何不正确的地方或者有额外的信息,那么请编辑它。


一,基本术语:

  • cron(8)是执行预定命令的守护进程。
  • crontab(1)是用来修改用户crontab(5)文件的程序。
  • crontab(5)是包含cron(8)指令的每个用户文件。

接下来,关于cron的教育:

系统上的每个用户都可能拥有自己的crontab文件。 根和用户crontab文件的位置取决于系统,但通常位于/var/spool/cron

有一个全系统的/etc/crontab文件, /etc/crontab 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守护进程未运行,并且运行命令的date/时间已过,则crond将无法追赶并运行查询。

crontab的细节,如何制定一个命令:

一个crontab命令由一行代表。 您不能使用\在多行上扩展命令。 散列( # )符号表示注释,意味着该行上的任何内容都被cron忽略。 领先的空白和空白行被忽略。

在命令中使用百分比( % )符号时要格外小心。 除非它们被转义\%否则它们会被转换成换行符,并且在第一个非转义%之后的所有内容都会在stdin中传递给您的命令。

有两种格式的crontab文件:

  • 用户crontabs

     # 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个字段表示应该运行该命令的时间。 您可以在时间说明中使用数字或适用的date/月份名称。

  • 这些字段由空格或制表符分隔。
  • 逗号( , )用于指定一个列表,例如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)等等

debuggingcron命令

检查邮件! 默认情况下,cron会把命令中的所有输出发送给正在运行命令的用户。 如果没有输出,就不会有邮件。 如果你想cron发送邮件到不同的帐户,那么你可以在crontab文件中设置MAILTO环境variables

 [email protected] 1 2 * * * /path/to/your/command 

捕获输出你自己

 1 2 * * * /path/to/your/command &>/tmp/mycommand.log 

它将stdout和stderr捕获到/tmp/mycommand.log

看日志; cron通过系统日志logging它的行为,这取决于你的设置,经常进入/var/log/cron/var/log/syslog

如果需要,你可以用例如过滤cron语句

 grep CRON /var/log/syslog 

现在我们已经了解了cron的基础知识,文件的位置以及如何使用它们,让我们看看一些常见的问题。

检查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 

可能有其他方法; 使用你的发行版提供的东西。

cron在受限制的环境中运行你的命令。

可用的环境variables可能非常有限。 通常情况下,您只会获得一些定义的variables,如$LOGNAME$HOME$PATH

特别值得注意的是, PATH仅限于/bin:/usr/bin绝大多数“我的cron脚本不起作用”的问题是由这个限制性的path引起的 。 如果您的命令位于不同的位置,可以通过以下几种方法解决:

  1. 提供您的命令的完整path。

     1 2 * * * /path/to/your/command 
  2. 在crontab文件中提供一个合适的PATH

     PATH=/usr:/usr/bin:/path/to/something/else 1 2 * * * command 

如果你的命令需要其他的环境variables,你也可以在crontab文件中定义它们。

cron用cwd == $ HOME运行你的命令

无论执行的程序位于文件系统的什么地方,当cron运行时程序的当前工作目录都将成为用户的主目录 。 如果你在你的程序中访问文件,如果你使用相对path,或者(最好)只是使用完全合格的path,那么你需要考虑这个问题,并为每个人节省很多的困惑。

我的crontab中的最后一个命令不运行

Cron通常要求命令以新行结束。 编辑你的crontab; 转到包含最后一条命令的行的末尾,并插入一个新行(按回车键)。

检查crontab格式

您不能在/ etc / crontab中使用用户crontab格式的crontab或/etc/cron.d中的碎片,反之亦然。 用户格式化的crontab在一行的第6个位置不包含用户名,而系统格式化的crontab包含用户名并以该用户的身份运行命令。

我把一个文件放在/etc/cron.$hourly,daily,weekly,monthly},它不运行

  • 检查文件名没有扩展名请参阅run-parts
  • 确保文件具有执行权限。
  • 告诉系统执行脚本时要使用什么(例如,把#!/bin/sh放在顶部)

克朗date相关的错误

如果您的date最近由用户或系统更新,时区或其他更改,那么crontab将开始行为不正常,并显示奇怪的错误,有时工作,有时不会。 这是crontab试图在时间从它下面改变时尝试“做你想做的事”。 小时改变后,“分钟”字段将无效。 在这种情况下,只有星号才会被接受。 重新启动cron并再次尝试,而不连接到互联网(所以date没有机会重置到其中一个时间服务器)。

如果您的cronjob停止工作,请检查您的密码是否过期,因为一旦它有,所有cron作业停止。
/var/log/messages中会显示类似于下面的/var/log/messages ,显示validation用户的问题:

(username) FAILED to authorize user with PAM (Authentication token is no longer valid; new one required)

Debian Linux及其派生版(Ubuntu,Mint等)有一些特性,可能会阻止您的cron作业执行; 尤其是/etc/cron.d的文件必须:

  • 归根
  • 只能由root写入
  • 不能被团体或其他用户书写
  • 有一个没有任何点的名字“。 或任何其他特殊字符,但“ – ”和“_”。

最后一个定期伤害用户; 特别是任何名为whatever.shmycron.pytestfile.pl等的文件夹中的任何脚本都不会被执行。

根据我的经验,这个特殊点是Debian和衍生产品上不执行cronjob的最常见原因。

如有必要,请参阅man cron以获取更多详细信息。

PHP专用

如果你有一些类似cron的工作:

 php /bla/bla/something.php >> /var/logs/somelog-for-stdout.log 

如果错误期望,他们将被发送给你,但他们不 – 检查这一点。

PHP默认不发送错误到STDOUT。 @请参阅https://bugs.php.net/bug.php?id=22839

要解决这个问题,请添加cli`s php.ini或者你的行(或者你的bash包装中的PHP):

  • –define display_startup_errors = 1
  • –define display_errors ='stderr'

第一个设置将允许你有像“记忆哎呀”和第二个 – redirect到STDERR的致命。 只有当你能睡好之后,所有的东西才会被发送到你的根邮件,而不是只logging下来。

罕见和不规则的时间表

Cron被认为是一个非常基本的调度器,语法不容易让pipe理员制定稍微不寻常的调度。

考虑下面通常会被解释为“每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,但在一小时和下一个 之间只有4分钟之间 ,00:56之后新的系列从01:00开始, 01:00 :07等(批量不会运行01:03等)。


该怎么做呢?

创build多个批次

而不是一个单一的cron作业,创build多个批次,将所需的时间表结合起来。

例如,每40分钟运行一批(00:00,00:40,01:20,02:00等),创build两个批次,一个在偶数小时运行两次,另一个只运行奇数小时:

 # The following lines create a batch that runs every 40 minutes ie # 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. 

less运行你的批次

而不是每7分钟运行一次,这是一个很难分批处理的时间表,而是每十分钟运行一次。

更频繁地运行你的批次

由于批处理运行时间增加/波动,因此许多奇怪的进度表会发生变化,然后批处理会得到一些额外的安全余量,从而防止同一批次的后续运行重叠并且同时运行。

相反,换个angular度思考,创build一个cronjob,当前一次运行尚未完成时,将会优雅地失败,但是否则将运行。 看到这个问答 :

 * * * * * /usr/bin/flock -n /tmp/fcj.lockfile /usr/local/bin/frequent_cron_job --minutely 

不要使用cron

如果你的需求很复杂,你可能会考虑使用一个更高级的产品来devise运行复杂的计划(分布在多个服务器上),并支持触发器,工作依赖,error handling,重试监控等行业术语将是“企业” 工作调度和/或“工作量自动化”。