当前位置: 首页>>技术问答>>正文


为什么crontab脚本不工作?

,

问题描述

通常情况下,crontab脚本未按计划执行或按预期执行。这有很多原因:

  1. 错误的crontab记法

  2. 权限问题

  3. 环境变量

此社区wiki旨在汇总crontab脚本未按预期执行的主要原因。将每个理由写在单独的答案中。

请在每个答案中包含一个原因 – 有关为什么不执行的详细信息 – 并针对这一原因进行修复。

请仅填写cron-specific问题,例如按照预期从shell执行的命令,但是由cron执行错误。

最佳解决方案

不同的环境

Cron将一组最小的环境变量传递给您的工作。要查看其差异,请添加如下所示的虚拟作业:

* * * * * env > /tmp/env.output

等待/tmp/env.output被创建,然后再次删除作业。现在将/tmp/env.output的内容与常规终端中运行的env的输出进行比较。

这里常见的”gotcha”是不同的PATH环境变量。也许你的cron脚本使用/opt/someApp/bin中找到的命令somecommand,你已经将它添加到/etc/environmentPATH中? cron忽略该文件中的PATH,因此,在脚本中运行somecommand时将失败,但在终端中运行时会失败。值得注意的是,来自/etc/environment的变量将被传递给cron作业,而不是cron特别设置的变量,比如PATH

为了解决这个问题,只需在脚本的顶部设置您自己的PATH变量即可。例如。

#!/bin/bash
PATH=/opt/someApp/bin:/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin

# rest of script follows

有些人更喜欢用绝对路径来代替所有的命令。我建议反对。考虑如果您想在不同的系统上运行脚本会发生什么情况,并且在该系统上,该命令是在/opt/someAppv2.2/bin中。您必须通过用/opt/someAppv2.2/bin替换/opt/someApp/bin的整个脚本,而不是在脚本的第一行上执行小编辑。

您还可以在crontab文件中设置PATH变量,该变量将应用于所有cron作业。例如。

PATH=/opt/someApp/bin:/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin

15 1 * * * backupscript --incremental /home /root

次佳解决方案

我最关心的问题:如果您忘记在crontab文件的末尾添加换行符。换句话说,crontab文件应该以空行结束。

以下是此问题的手册页中的相关部分(man crontab然后跳到最后):

   Although cron requires that each entry in a crontab end  in  a  newline
   character,  neither the crontab command nor the cron daemon will detect
   this error. Instead, the crontab will appear to load normally. However,
   the  command  will  never  run.  The best choice is to ensure that your
   crontab has a blank line at the end.

   4th Berkeley Distribution      29 December 1993               CRONTAB(1)

第三种解决方案

Cron守护进程没有运行。几个月前我真的搞砸了。

类型:

pgrep cron 

如果你看不到数字,那么cron没有运行。 sudo /etc/init.d/cron start可用于启动cron。

编辑:而不是通过/etc/init.d调用init脚本,使用服务实用程序,例如

sudo service cron start

第四种方案

cron.d/cron.daily/cron.hourly/等中的脚本文件名不应包含点(.),否则run-parts将跳过它们。

参见run-parts(8):

   If neither the --lsbsysinit option nor the --regex option is given then
   the names must consist entirely of upper and lower case  letters,  dig‐
   its, underscores, and hyphens.

   If  the  --lsbsysinit  option  is given, then the names must not end in
   .dpkg-old  or .dpkg-dist or .dpkg-new or .dpkg-tmp, and must belong  to
   one  or more of the following namespaces: the LANANA-assigned namespace
   (^[a-z0-9]+$);   the   LSB   hierarchical   and   reserved   namespaces
   (^_?([a-z0-9_.]+-)+[a-z0-9]+$);  and  the  Debian cron script namespace
   (^[a-zA-Z0-9_-]+$).

因此,如果您在cron.daily/目录中有backup.shanalyze-logs.pl cron脚本,最好删除扩展名。

第五种方案

在许多环境中,cron使用sh执行命令,而许多人认为它将使用bash

测试或修复失败命令的建议:

  • 尝试在sh中运行该命令以查看它是否有效

  • 将命令封装在bash子shell中以确保它在bash中运行:bash -c "mybashcommand"

  • 通过设置crontab顶部的shell来告诉cron在bash中运行所有命令:SHELL=/bin/bash

  • 如果该命令是脚本,请确保该脚本包含一个shebang:#!/bin/bash

第六种方案

我在时区上遇到了一些问题。 Cron正在运行新的安装时区。解决方案是重新启动cron:

sudo service cron restart

第七种方案

如果您的crontab命令中包含%符号,cron会尝试解释它。因此,如果您在其中使用任何带有%的命令(例如date命令的格式说明),则需要将其转义。

这和其他好的陷阱在这里:http://www.pantz.org/software/cron/croninfo.html

第八种方案

脚本应该使用绝对路径:

例如,应该使用/bin/grep来代替grep

# m h  dom mon dow   command
0 0 *  *  *  /bin/grep ERROR /home/adam/run.log &> /tmp/errors

代替:

# m h  dom mon dow   command
0 0 *  *  *  grep ERROR /home/adam/run.log &> /tmp/errors

这是特别棘手的,因为从shell执行相同的命令将工作。原因是cron没有与用户相同的PATH环境变量。

第九种方案

用户的密码也可能已过期。即使root的密码也可以过期。你可以tail -f /var/log/cron.log,你会看到cron失败,密码过期。您可以通过执行此操作将密码设置为永不过期:passwd -x -1 <username>

在某些系统(Debian,Ubuntu)中,默认情况下未启用cron日志记录。在/etc/rsyslog.conf或/etc/rsyslog.d/50-default.conf行中:

# cron.*                          /var/log/cron.log

应该被编辑(sudo nano /etc/rsyslog.conf)取消注释为:

cron.*                          /var/log/cron.log

之后,您需要通过重新启动rsyslog

/etc/init.d/rsyslog restart

要么

service rsyslog restart 

来源:Enable crontab logging in Debian Linux

在某些系统(Ubuntu)中,默认情况下未启用cron单独的日志文件,但cron相关日志出现在syslog文件中。可以使用

cat /var/log/syslog | grep cron

查看cron-related消息。

第十种方案

Cron正在调用一个不可执行的脚本。

通过运行chmod +x /path/to/scrip该脚本变为可执行文件并应解决此问题。

参考资料

本文由Ubuntu问答整理, 博文地址: https://ubuntuqa.com/article/52.html,未经允许,请勿转载。