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


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

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

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


193
2017-11-17 04:51




这是一个巨大的骗局 crontab不起作用的原因 在AskUbuntu上。 - Dan Dascalescu


答案:


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


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


一,基本术语:

接下来,关于cron的教育:

系统上的每个用户都可以拥有自己的crontab文件。 root和用户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命令由单行表示。你不能用 \ 在多行上扩展命令。哈希(#)sign表示注释,表示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环境变量,例如

MAILTO=user@somehost.tld
1 2 * * * /path/to/your/command

自己捕获输出

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

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

看看日志; cron通过syslog记录它的动作,这经常会去(取决于你的设置) /var/log/cron 要么 /var/log/syslog

如果需要,您可以使用例如cron语句过滤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=/usr:/usr/bin:/path/to/something/else
    1 2 * * * command 
    

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

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

无论您执行的程序驻留在文件系统的哪个位置,当cron运行它时程序的当前工作目录都将是 用户的主目录。如果您访问程序中的文件,如果您使用相对路径,或者(最好)只是在所有地方使用完全限定的路径,则需要考虑这一点,并为每个人节省大量的困惑。

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

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

检查crontab格式

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

我在/etc/cron.{hourly,daily,weekly,monthly}中放了一个文件,它没有运行

  • 检查文件名没有扩展名 运行部分
  • 确保该文件具有执行权限。
  • 告诉系统执行脚本时要使用什么(例如put #!/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")"

273
2017-10-09 15:29



可能还想在“受限制的env”部分中提到LD_LIBRARY_PATH可能还需要设置任何其他目录,以防您的cron任务因无法找到共享库而失败。 - DavidJ
请注意,你甚至可以写这样的东西:35 1,5-23 / 2 * * * do_something而不是35,1,5,7,9,.. * * *此外这个 crontab.guru 将您输入的条目翻译为人类语言。 - Dennis Nolte
输出捕获对我不起作用,可能是因为sh shell。我认为这更便携: ... /path/to/your/command >/tmp/mycommand.log 2>&1 - chus
这对我有用: sudo apt-get install postfix - jmunsch
cron的工作还取决于文件有多重?因为我用cron在python中运行简单的hello world,所以它很有效。但我的第二个代码有点沉重,通常会运行但是使用cron它不会给文件输出任何内容。 - Devendra Bhat


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

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


18
2018-02-04 20:29



刚刚得到这个(错误消息文件/ var / log / syslog对我来说)。在我的情况下,一个DigitalOcean盒子,在创建时,他们将root密码(可选)重置为另一个,显然直到你进入并更改它,所有cron作业都不会运行。游民。修复是这样的 sudo -u root passwd - rogerdpack


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

  • 由root拥有
  • 只能由root写入
  • 不可由组或其他用户写入
  • 有一个名字 没有任何点'。' 或任何其他特殊字符,但' - '和'_'。

最后一个经常伤害毫无戒心的用户;特别是其中一个命名的文件夹中的任何脚本 whatever.shmycron.pytestfile.pl等等  被执行,永远。

根据我的经验,这个特定点是迄今为止在Debian和衍生品上不执行cronjob的最常见原因。

看到 man cron 如有必要,请提供更多详情。


15
2017-11-17 14:37





不常见和不定期的时间表

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:0001: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 --minutely

在类似的说明中,您可以批量记录上次成功运行的时间戳,并在批次检查开始时检查批次之间的所需间隔是否已经过并执行,否则优雅地退出。

在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
    echo "The minimum interval of 7 minutes between successive batches hasn't passed yet."
    exit
fi

echo "Start running your batch"

date > /tmp/lastrun

然后您可以安全地(尝试)每分钟运行一次:

* * * * * /path/to/your/seven-minute-job

不要使用cron

如果您的需求很复杂,您可以考虑使用更高级的产品,该产品旨在运行复杂的计划(分布在多个服务器上),并支持触发器,作业依赖,错误处理,重试监控等。行业术语将是“企业” 工作安排 和/或“工作量自动化”。


10
2017-10-23 04:45





PHP专用

如果你有一些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或在你的行中(或在你的bash包装中为PHP):

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

第一个设置将允许你有'内存oops'和第二个 - 致命,将它们全部重定向到STDERR。只有在你能睡得好之后才能将所有内容发送到root用户的邮箱,而不是仅仅记录下来。


8



该错误报告于2007年关闭,补丁的状态被添加到PHP 5.2+分支。你确定需要吗?我刚刚尝试了PHP 5.4,它似乎工作正常。 (虽然PHP 4仍然需要它)。 - Xeoncross
@Xeoncross看到答案日期:) - gaRex
是的,自从你在2013年回答并且机票在07年回来后,这让我很困惑。 - Xeoncross