为什么我的 crontab 不工作?我该如何排除故障?

为什么我的 crontab 不工作?我该如何排除故障?

这是一个典型问题关于使用 cron 和 crontab。

您被引导到这里是因为社区确信您的问题的答案可以在下面找到。如果您的问题没有在下面找到答案,那么答案将帮助您收集信息,从而帮助社区帮助您。这些信息应该被编辑到您的原始问题中。

答案是为什么我的 crontab 不工作?我该如何排除故障?' 如下所示。这将使cron系统以 crontab 突出显示。

答案1

如何修复所有与 crontab 相关的麻烦/问题(Linux)


这是一个社区维基,如果您发现此答案有任何错误或有其他信息,请编辑它。


一、基本术语:

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

接下来,关于 cron 的教育:

系统上的每个用户可能都有自己的 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 详情,如何制定命令:

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 个字段表示应运行命令的时间。时间规范中可以使用数字或适当的日期/月份名称。

  • 字段之间以空格或制表符分隔。
  • 逗号 ( ,) 用于指定列表,例如 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 会将命令的任何输出通过邮件发送给运行该命令的用户。如果没有输出,则不会发送邮件。如果您希望 cron 将邮件发送到其他帐户,则可以在 crontab 文件中设置 MAILTO 环境变量,例如

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

自己捕获输出

您可以将 stdout 和 stderr 重定向到文件。捕获输出的确切语法可能因 cron 使用的 shell 而异。以下是将所有输出保存到文件的两个示例/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 是否正在运行

如果 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 在受限环境中运行您的命令。

可用的环境变量可能非常有限。通常,您只会定义几个变量,例如$LOGNAME$HOME$PATH

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

  1. 提供命令的完整路径。

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

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

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

cron 使用 cwd == $HOME 运行您的命令

无论你执行的程序位于文件系统的什么位置,cron 运行时程序的当前工作目录将是用户的主目录。如果您在程序中访问文件,则需要考虑到使用相对路径的情况,或者(最好)在任何地方都使用完全限定路径,这样可以避免大家产生很多困惑。

我的 crontab 中的最后一条命令没有运行

Cron 通常要求命令以新行结尾。编辑您的 crontab;转到包含最后一条命令的行尾并插入新行(按 Enter)。

检查 crontab 格式

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

我将文件放入 /etc/cron.{hourly,daily,weekly,monthly} 但它没有运行

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

Cron 日期相关错误

如果您的日期最近被用户或系统更新、时区或其他因素更改,那么 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")"

如何sudo在 cron 任务中使用

以非 root 用户身份运行时,

crontab -e

将打开用户的 crontab,同时

sudo crontab -e

将打开 root 用户的crontab。不建议sudo用户cron 任务,因此如果你的 cron 任务需要 root 权限,那么你应该以 root 权限运行该任务crontab从命令中删除 sudo

答案2

Debian Linux 及其衍生产品(Ubuntu、Mint 等)有一些特性,可能会阻止您的 cron 作业执行;特别是中的文件/etc/cron.d必须/etc/cron.{hourly,daily,weekly,monthly}

  • 由 root 拥有
  • 仅可由 root 写入
  • 不可由组或其他用户写入
  • 有名字没有任何点 '.'或除 '-' 和 '_' 之外的任何其他特殊字符。

最后一个漏洞会经常伤害毫无戒心的用户;特别是位于以下文件夹中名为whatever.shmycron.pytestfile.pl等文件夹中的任何脚本都会不是永远被处决。

根据我的经验,这个特定点是 Debian 和衍生版本中 cronjob 无法执行的最常见原因。

如果有必要的话,请参阅man cron更多详细信息。

答案3

如果您的 cronjobs 停止工作,请检查您的密码是否过期。因为一旦密码过期,所有 cron 作业都会停止。
将出现/var/log/messages类似于下面的消息,显示用户身份验证问题:

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

答案4

PHP 专用

如果你有如下 cron 任务:

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

如果出现错误,系统会将其发送给您,但是却没有——请检查一下。

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

为了修复这个问题,在 cli 的 php.ini 或你的行中(或者在你的 PHP 的 bash 包装器中)添加这些:

  • --定义 display_startup_errors = 1
  • --define display_errors='stderr'

第一种设置将允许您遇到“内存错误”等致命错误,第二种设置 — 将它们全部重定向到 STDERR。只有这样您才能高枕无忧,因为所有错误都将发送到您的根邮件,而不仅仅是记录下来。

相关内容