cronjob 不执行独立运行的脚本

Posted

技术标签:

【中文标题】cronjob 不执行独立运行的脚本【英文标题】:cronjob does not execute a script that works fine standalone 【发布时间】:2016-08-21 12:29:04 【问题描述】:

我的 php 脚本文件位于 /var/www/html/dbsync/index.php。当cd /var/www/html/dbsync/ 并运行php index.php 时,它可以完美运行。

我想通过sh文件调用php文件,sh文件的位置如下

/var/www/html/dbsync/dbsync.sh

这是dbsync.sh文件的内容是:

/usr/bin/php /var/www/html/dbsync/index.php >> /var/www/html/dbsync/myscript.log 2>&1 -q -f

当我 cd /var/www/html/dbsync/ 并运行 ./dbsync.sh 时,它也能完美运行。

现在如果我如下设置 crontab:

1 * * * * /var/www/html/dbsync/dbsync.sh /var/www/html/dbsync

但是,这个 crontab 没有按预期工作。

有什么问题?

【问题讨论】:

第二个 /var/www/html/dbsync 是干什么用的? /var/www/html/dbsync - dbsync 是 index.php 和 dbsync.sh 文件的保存目录。 现在我想尝试每一秒。稍后,如果执行所需的结果,我将每天设置为午夜 你能把所有这些命令放在另一个文件中,让它以chmod +x filename 执行,然后将该文件添加到crontab 中吗?让我知道结果。 你应该指定二进制文件来执行 sh 脚本 --> 1 * * * * /bin/sh /var/www/html/dbsync/dbsync.sh /var/www/html/dbsync 或者你说which sh 得到的任何东西。 【参考方案1】:

正如在 cmets 中看到的那样,问题在于您没有定义应该使用什么程序来执行脚本。考虑到 cronjob 是在很小的环境中执行的;在那里,不能假设太多。这就是我们定义完整路径等的原因。

所以你需要这样说:

1 * * * * /bin/sh /var/www/html/dbsync/dbsync.sh /var/www/html/dbsync
#         ^^^^^^^

/bin/sh 是您要用于执行脚本的二进制文件。

否则,您可以为脚本设置执行权限并添加shell-script header 告诉它使用什么解释器:

#!/bin/sh

如果这样做,则不需要添加二进制文件的路径。

来自Troubleshooting common issues with cron jobs:

使用相对路径。如果您的 cron 作业正在执行一些脚本 种类,您必须确保在该脚本中仅使用绝对路径。 例如,如果您的脚本位于 /path/to/script.php 并且 您正在尝试在同一目录中打开一个名为 file.php 的文件, 您不能使用诸如 fopen(file.php) 之类的相对路径。该文件必须 从其绝对路径调用,如下所示:fopen(/path/to/file.php)。 这是因为 cron 作业不一定从目录中运行 脚本所在的位置,所以必须专门调用所有路径。


另外,我了解您希望每分钟运行一次。如果是这样,1 * * * * 就不行了。 Intead,它将运行at every 1st minute past every hour。因此,如果您想每分钟运行一次,请说* * * * *

【讨论】:

谢谢@fedorqui 这工作得很好,我会记住要提到应该使用哪个程序来执行脚本。 @sanainfotech 不客气 :) 你提供了很多细节,所以我试图使答案足够通用,以便在其他情况下用作参考。【参考方案2】:

理解“login shell”和“interactive shell”的含义很重要。

login shell:当您使用 ssh session 登录并获得一个终端窗口时,您可以在其中输入 shell 命令。登录后系统会执行一些文件(.bashrc)并为您设置一些环境变量,例如PATH变量。 交互式shell:登录系统后,您可以手动启动shell终端。系统执行分配给您帐户的一些配置文件(.bash_profile、.bash_login、.profile)。该文件还为您手动打开的 shell 会话设置一些环境变量并初始化 PATH 变量。

由操作系统启动的 shell 脚本和 cron 作业不适合上述启动 shell 的方式。因此不会执行任何系统脚本(.bashrc)或用户配置文件。这意味着我们的 PATH 变量没有被初始化。找不到 Shell 命令,因为 PATH 变量未指向正确的位置。

这解释了为什么您的脚本在手动启动时运行成功,但在您通过 crontab 启动时失败。

解决方案 1: 使用每个 shell 命令的绝对路径,而不是仅使用脚本文件中使用的命令名称。

使用“/usr/bin/awk”代替“awk” 用“/bin/sed”代替“sed”

Solution-2:在执行shell脚本之前初始化环境变量,尤其是PATH变量!

【讨论】:

因为可以在 在 crontab 本身中设置一个PATH(即使在初始条目中,但在文件的顶部 - 任何 key=value 对会自动导出到环境中),这个答案似乎没有明确讨论这种简单的方法来完成它的命令。【参考方案3】:

方法一,在你的dbsync.sh中添加这个头文件:

#!/bin/bash -l

方法2,在你的cron文件中添加bash -l:

1 * * * * bash -l /var/www/html/dbsync/dbsync.sh /var/www/html/dbsync

【讨论】:

请问#!/bin/bash -l是什么意思 阅读手册。 -l 选项表示将 Bash 作为登录 shell 调用,它会读取更多的配置文件(尽管仍与指定 interactive 模式的-i 完全相同)。

以上是关于cronjob 不执行独立运行的脚本的主要内容,如果未能解决你的问题,请参考以下文章

为啥 crontab 不执行我的 PHP 脚本?

如何检查 Linux shell 脚本是不是由 cronjob 执行?

CronJob只执行一次

Cronjob 卡住而不退出

调度php脚本?

ubuntu使用脚本调用脚本,并用cron做定时任务,为啥执行不了