为什么 crontab 脚本不起作用?

Ada*_*tan 604 cron

通常,crontab脚本不会按计划或按预期执行。有很多原因:

  1. 错误的 crontab 符号
  2. 权限问题
  3. 环境变量

该社区维基旨在汇总crontab脚本未按预期执行的主要原因。在单独的答案中写下每个原因。

请在每个答案中包含一个原因 - 未执行原因的详细信息 - 并针对该原因进行修复。

请只编写特定于 cron 的问题,例如在 shell 中按预期执行但被 cron 错误执行的命令。

gei*_*rha 583

不同的环境

Cron 将最少的一组环境变量传递给您的作业。要查看差异,请添加这样的虚拟作业:

* * * * * 环境 > /tmp/env.output

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

这里一个常见的“问题”是PATH环境变量不同。也许您的 cron 脚本使用了在 中somecommand找到的命令/opt/someApp/bin,您已将其添加到PATH/etc/environment?cron 会忽略PATH该文件,因此somecommand在使用 cron 运行时,从脚本运行将失败,但在终端中运行时可以工作。值得注意的是,变量 from/etc/environment将传递给 cron 作业,而不是 cron 专门设置的变量,例如PATH.

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

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

有些人更喜欢只使用所有命令的绝对路径。我建议反对。考虑一下如果您想在不同的系统上运行脚本会发生什么,而在该系统上,命令是在其中/opt/someAppv2.2/bin。您必须遍历整个脚本,替换为/opt/someApp/bin/opt/someAppv2.2/bin而不仅仅是对脚本的第一行进行小的编辑。

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

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

# rest of script follows
Run Code Online (Sandbox Code Playgroud)

  • 对于`env` +1,我完全忘记了那个命令,并认为 PATH 正在工作。就我而言,这实际上略有不同。 (9认同)
  • @pbr 如果此类目录可供其他人写入,则系统已经受到损害。 (9认同)
  • 我想我只是为此而堕落,最后换行......双重打击。 (6认同)
  • @pbr 系统管理员可能会无意中删除根文件系统。您无法防止系统管理员犯下愚蠢的错误。如果您安装了不向后兼容的较新版本的解释器,我希望无论如何都会损坏。处理该问题的明智方法是将其安装为不同的命令。例如,你有 python 版本 2.x 并安装了 python 3,你将它安装为 python3,而不是 python。至于/opt/someApp/bin,为什么它没有健全的权限/所有权?任何理智的管理员都会确保对系统文件的理智权限/所有权。 (6认同)
  • @pbr 看来我们可以永远继续下去,是的。我仍然不明白为什么使用 PATH 是个坏主意。如果你想在更适合讨论的媒体中进一步讨论这个问题,你会在 #ubuntu 和 #bash 以及其他频道中找到我,在 irc.freenode.net (2认同)

use*_*124 394

我的首要问题:如果您忘记在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)
Run Code Online (Sandbox Code Playgroud)

  • 这么牛逼,怎么这么多年cron还没修好? (117认同)
  • @barraponto 这实际上是新文本编辑器中的一个错误。“换行”字符应该是一个_行终止_字符,所以文本文件中的最后一行应该以一个不会在编辑器中显示的换行符结束。Vi 和 vim 正确使用了这个字符,并且 cron 是在新编辑器开始他们奇怪的行为之前构建的......因此播放它并保存并包含一个空行。 (21认同)
  • 如果您使用 `crontab -e` 编辑 crontab,它将在允许保存之前检查文件的语法,包括检查换行符。 (8认同)
  • 似乎在 Vixie cron 中已修复:Ubuntu 10.10 上的 `man crontab` 表示“cron 要求 crontab 中的每个条目都以换行符结尾。如果 crontab 中的最后一个条目缺少换行符,cron 将考虑 crontab(在至少部分)损坏并拒绝安装它。” (最后的日期是 2010 年 4 月 19 日。) (2认同)
  • @Chan-HoSuh,根据手册页“cron 要求 crontab 中的每个条目都以换行符结尾。如果 crontab 中的最后一个条目缺少换行符,cron 将认为 crontab(至少部分)损坏并拒绝安装它。” 此行为将在编辑然后使用 `-e` 选项保存 crontab 时调用,并且独立于编辑器。 (2认同)

ane*_*hep 166

Cron 守护程序未运行。几个月前我真的搞砸了。

类型:

pgrep cron 
Run Code Online (Sandbox Code Playgroud)

如果没有看到数字(即 cron 的主 PID),则 cron 没有运行。sudo /etc/init.d/cron start可以用来启动cron。

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

sudo service cron start
Run Code Online (Sandbox Code Playgroud)

编辑:您也可以在现代 Linux 中使用 systemctl,例如

sudo systemctl start cron
Run Code Online (Sandbox Code Playgroud)

  • 感谢您向我展示 pgrep。我一直在做 ps -ef | grep foo (56认同)
  • 你也可以使用`pidof cron`,它会省略其他也有“cron”这个词的应用程序的结果,比如crontab。 (4认同)
  • `service crond start` 如果是 centos/RHEL (3认同)

Xiè*_*léi 104

在脚本文件名cron.d/cron.daily/cron.hourly/等,不应包含点(.),否则运行部分将跳过他们。

参见运行部分(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_-]+$).
Run Code Online (Sandbox Code Playgroud)

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

  • 这是一个功能而不是错误 - 它使 myscript.backup 或 myscript.original 或 myscript.rpm-new 之类的东西无法在 myscript 旁边运行。 (11认同)
  • 如果这是一个功能,它不是一个很好的功能:(很多人在文件名中使用点(backup.sh是最常见的)。如果你想让脚本停止执行,最合乎逻辑的方法是从“cron.d”目录中删除它。 (11认同)
  • 这是一个如此糟糕的功能,它实际上是一个错误。如果人们想确保事情只在预期的时候运行,通常的做法是要求一个特定的结尾(比如“.list”或“.cron”或其他东西)。随意选择点作为“.bak”或“.temp”或其他任何东西的可能分隔符是完全不可预测的,除非它会以可预见的方式混淆人们。像“.sh”和“.pl”这样的合法结尾已经被广泛使用了几十年。然而,很多人使用“_bak”或“_temp”或“-bak”而不是点。这是一个糟糕的设计选择;这充其量只是一个设计错误。 (10认同)

Ian*_*non 82

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

针对失败的命令测试或修复此问题的建议:


小智 49

我对时区有一些问题。Cron 以全新安装时区运行。解决方案是重新启动cron:

sudo service cron restart
Run Code Online (Sandbox Code Playgroud)

  • 是的,在系统上更改时区后,必须重新启动每个关心时间的服务,或者重新启动。我更喜欢重启,以确保我已经抓住了一切。 (7认同)

Ada*_*tan 42

脚本应该使用绝对路径:

例如,/bin/grep应该使用而不是grep

# m h  dom mon dow   command
0 0 *  *  *  /bin/grep ERROR /home/adam/run.log &> /tmp/errors
Run Code Online (Sandbox Code Playgroud)

代替:

# m h  dom mon dow   command
0 0 *  *  *  grep ERROR /home/adam/run.log &> /tmp/errors
Run Code Online (Sandbox Code Playgroud)

这尤其棘手,因为在从 shell 执行时,相同的命令将起作用。原因是它cron没有PATH与用户相同的环境变量。

  • 呸。您不需要定义 PATH - 使用绝对路径是这里的最佳实践。“因为可执行文件可能在其他计算机上的其他地方”并不能胜过“我希望它完全运行这个程序,而不是其他人放在我原始程序前面的路径中” (11认同)
  • 参见 geirha 答案,您可以(必须)定义 cron 的 PATH (3认同)

小智 37

如果您的 crontab 命令中有一个%符号,cron 会尝试解释它。因此,如果您正在使用任何带有 a 的命令%(例如日期命令的格式规范),您将需要对其进行转义。

这里还有其他好的问题:http :
//www.pantz.org/software/cron/croninfo.html

  • 另请参阅[如何在 cron 选项卡作业中执行 `date`?](https://unix.stackexchange.com/questions/29578/how-can-i-execute-date-inside-of-a-cron -tab-job) (2认同)

jet*_*jet 28

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

通过运行chmod +x /path/to/script,脚本变得可执行,这应该可以解决这个问题。

  • 这不是 `cron` 独有的,只需尝试从命令行执行 `/path/to/script` 即可轻松追踪。 (6认同)
  • 如果您习惯于使用 `. scriptname` 或 `sh scriptname` 或 `bash scriptname`,那么这将成为 `cron` 特定的问题。 (4认同)

小智 27

用户的密码也可能已过期。甚至 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
Run Code Online (Sandbox Code Playgroud)

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

cron.*                          /var/log/cron.log
Run Code Online (Sandbox Code Playgroud)

之后,您需要通过以下方式重新启动 rsyslog

/etc/init.d/rsyslog restart
Run Code Online (Sandbox Code Playgroud)

或者

service rsyslog restart 
Run Code Online (Sandbox Code Playgroud)

来源:在 Debian Linux 中启用 crontab 日志记录

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

cat /var/log/syslog | grep cron -i
Run Code Online (Sandbox Code Playgroud)

查看与 cron 相关的消息。


小智 20

如果您的 cronjob 调用 GUI 应用程序,您需要告诉他们应该使用什么 DISPLAY。

示例:使用 cron 启动 Firefox。

您的脚本应该包含export DISPLAY=:0某处。


小智 18

不安全的 cron 表权限

如果 cron 表的权限不安全,它会被拒绝

sudo service cron restart
grep -i cron /var/log/syslog|tail -2
2013-02-05T03:47:49.283841+01:00 ubuntu cron[49906]: (user) INSECURE MODE (mode 0600 expected) (crontabs/user)
Run Code Online (Sandbox Code Playgroud)

问题解决了

# correct permission
sudo chmod 600 /var/spool/cron/crontabs/user
# signal crond to reload the file
sudo touch /var/spool/cron/crontabs
Run Code Online (Sandbox Code Playgroud)


小智 15

权限问题很常见,恐怕。

请注意,一个常见的解决方法是使用 root 的 crontab 执行所有内容,这有时是一个非常糟糕的主意。设置适当的权限绝对是一个很大程度上被忽视的问题。


pjm*_*rse 13

脚本是位置敏感的。这与在脚本中始终使用绝对路径有关,但并不完全相同。您的 cron 作业cd在运行之前可能需要到特定目录,例如 Rails 应用程序上的 rake 任务可能需要在应用程序根目录中,以便 Rake 找到正确的任务,更不用说适当的数据库配置等。

所以一个 crontab 条目

23 3 * * * /usr/bin/rake db:session_purge RAILS_ENV=production

会更好

23 3 * * * cd /var/www/production/current && /usr/bin/rake db:session_purge RAILS_ENV=production

或者,为了让 crontab 条目更简单、更不脆弱:

23 3 * * * /home/<user>/scripts/session-purge.sh

使用以下代码/home/<user>/scripts/session-purge.sh

cd /var/www/production/current
/usr/bin/rake db:session_purge RAILS_ENV=production

  • 如果从 cron 调用的脚本是用 PHP 等解释性语言编写的,您可能需要在脚本本身中设置工作目录。例如,在 PHP 中:`chdir(dirname(__FILE__));` (2认同)

pbr*_*pbr 12

当从一个 crontab 文件移动到另一个时,过去有效的Crontab 规范可能会中断。有时原因是您已将规范从系统 crontab 文件移至用户 crontab 文件,反之亦然。

cron 作业规范格式在用户的 crontab 文件(/var/spool/cron/username 或 /var/spool/cron/crontabs/username)和系统 crontabs(/etc/crontab以及 中的文件/etc/cron.d)之间有所不同。

系统 crontab 在要运行的命令之前有一个额外的字段“用户”。

这将导致错误说明诸如george; command not found何时将命令移出/etc/crontab或将文件/etc/cron.d移入用户的 crontab 文件。

相反,/usr/bin/restartxyz is not a valid username当反向发生时,cron 会传递类似或类似的错误。


Bil*_*hor 12

我看到 cron 在错误陈述的时间表中失败的最常见原因。需要练习将安排在晚上 11:15 的作业指定15 23 * * ** * 11 15 *11 15 * * *。午夜之后工作的星期几也变得混乱 MF 是2-6在午夜之后,而不是1-5。具体日期通常是一个问题,因为我们很少使用它们* * 3 1 *不是 3 月 3 日。如果您不确定,请访问https://crontab.guru/在线检查您的 cron 计划。

如果您在不同平台上使用不受支持的选项(例如2/3时间规范)也可能导致失败。这是一个非常有用的选项,但并非普遍可用。我也遇到过像1-5或 之类的列表的问题1,3,5

使用不合格的路径也会导致问题。默认路径通常是/bin:/usr/bin这样,只有标准命令才会运行。这些目录通常没有所需的命令。这也会影响使用非标准命令的脚本。其他环境变量也可能丢失。

完全破坏现有的 crontab 给我带来了问题。我现在从文件副本加载。crontab -l如果它被破坏,可以从现有的 crontab 中恢复。我将 crontab 的副本保存在 ~/bin 中。它贯穿始终并以行结束# EOF。这是每天从 crontab 条目重新加载的,例如:

#!/usr/bin/crontab
# 重新加载这个 crontab
#
54 12 * * * ${HOME}/bin/crontab

上面的 reload 命令依赖于一个可执行的 crontab,带有运行 crontab 的 bang 路径。某些系统需要在命令中运行 crontab 并指定文件。如果目录是网络共享的,那么我经常使用crontab.$(hostname)作为文件名。这最终将纠正在错误服务器上加载错误 crontab 的情况。

使用该文件提供了 crontab 应该是什么的备份,并允许crontab -e自动取消临时编辑(我唯一使用的时间)。有可用的标题有助于获得正确的调度参数。当没有经验的用户编辑 crontab 时,我已经添加了它们。

我很少遇到需要用户输入的命令。这些在 crontab 下失败,尽管有些可以使用输入重定向。

  • 你能解释一下 `30 23 * * * ` 是如何翻译成晚上 11:15 的吗? (9认同)
  • 这包括三个不同的问题。它们可以分成单独的答案吗? (3认同)

小智 11

如果你有这样的命令:

* * * * * /path/to/script >> /tmp/output
Run Code Online (Sandbox Code Playgroud)

并且它不起作用并且您看不到任何输出,这可能并不一定意味着 cron 不起作用。脚本可能会被破坏,输出到stderr而不会传递到 /tmp/output。通过捕获此输出来检查情况并非如此:

* * * * * /path/to/script >> /tmp/output 2>&1
Run Code Online (Sandbox Code Playgroud)

看看这是否有助于您解决问题。


小智 10

cron 脚本正在使用 --verbose 选项调用命令

我的 cron 脚本失败了,因为我在键入脚本时处于自动驾驶状态,并且我包含了 --verbose 选项:

#!/bin/bash
some commands
tar cvfz /my/archive/file.tar.gz /my/shared/directory
come more commands
Run Code Online (Sandbox Code Playgroud)

从 shell 执行时脚本运行良好,但从 crontab 运行时失败,因为从 shell 运行时详细输出会转到 stdout,但从 crontab 运行时无处可去。删除“v”的简单修复:

#!/bin/bash
some commands
tar cfz /my/archive/file.tar.gz /my/shared/directory
some more commands
Run Code Online (Sandbox Code Playgroud)

  • 为什么这会导致失败?缓冲问题? (5认同)

小智 7

如果您通过 SSH 密钥访问帐户,则可以登录该帐户但不会注意到该帐户的密码已被锁定(例如,由于密码过期或无效的密码尝试)

如果系统正在使用 PAM 并且帐户被锁定,这可能会阻止其 cronjob 运行。(我已经在 Solaris 上测试过了,但没有在 Ubuntu 上测试过)

您可能会在 /var/adm/messages 中找到这样的消息:

10 月 24 日 07:51:00 mybox cron[29024]:[ID 731128 auth.notice] pam_unix_account:cron 试图从本地主机验证锁定帐户 myuser
10 月 24 日 07:52:00 mybox cron[29063]:[ID 731128 auth.notice] pam_unix_account:cron 试图从本地主机验证锁定帐户 myuser
10 月 24 日 07:53:00 mybox cron[29098]:[ID 731128 auth.notice] pam_unix_account:cron 试图从本地主机验证锁定帐户 myuser
10 月 24 日 07:54:00 mybox cron[29527]:[ID 731128 auth.notice] pam_unix_account:cron 试图从本地主机验证锁定帐户 myuser

您需要做的就是运行:

# passwd -u <用户名>

以 root 身份解锁帐户,crontab 应该再次工作。