cronjob 不执行独立运行的脚本
cronjob does not execute a script that works fine standalone
我在 /var/www/html/dbsync/index.php
中有我的 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 没有按预期工作。
有什么问题吗?
正如评论中所见,问题是您没有定义应该使用什么程序来执行脚本。考虑到 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:
Using relative paths. If your cron job is executing a script of some
kind, you must be sure to use only absolute paths inside that script.
For example, if your script is located at /path/to/script.phpand
you're trying to open a file called file.php in the same directory,
you cannot use a relative path such as fopen(file.php). The file must
be called from its absolute path, like this: fopen(/path/to/file.php).
This is because cron jobs do not necessarily run from the directory in
which the script is located, so all paths must be called specifically.
另外,我知道你想 运行 每分钟都这样。如果是这样,1 * * * *
就不行了。相反,它将 运行 at every 1st minute past every hour。所以如果你想每分钟 运行 它,说 * * * * *
.
了解 "login shell" 和 "interactive shell" 它们的含义很重要。
- 登录 shell:当您使用 ssh 会话登录并获得一个终端 window 时,您可以在其中输入 shell 命令。登录后系统会执行一些文件(.bashrc)并为您设置一些环境变量,例如PATH变量。
- 交互式shell :登录系统后,您可以手动启动shell个终端。系统执行分配给您帐户的一些配置文件 (.bash_profile, .bash_login,.profile)。此文件还设置了一些环境变量并为您手动打开的 shell 会话初始化 PATH 变量。
通过 OS 启动 shell 脚本和 cron 作业不适合上述启动 shell 的方式。因此,不会执行任何系统脚本(.bashrc)或用户配置文件。这意味着我们的 PATH 变量没有被初始化。 Shell 找不到命令,因为 PATH 变量没有指向正确的位置。
这解释了为什么您的脚本在手动启动时运行成功,但在通过 crontab 启动时失败。
解法一:
使用每个 shell 命令的绝对路径,而不是仅使用脚本文件中使用的命令名称。
- 而不是 "awk" 使用“/usr/bin/awk”
- 而不是 "sed" 使用“/bin/sed”
解决方案2:在执行shell脚本之前初始化环境变量,尤其是PATH变量!
方法一,在你的dbsync.sh中添加这个header:
#!/bin/bash -l
方法二,在你的cron文件中添加bash -l:
1 * * * * bash -l /var/www/html/dbsync/dbsync.sh /var/www/html/dbsync
我在 /var/www/html/dbsync/index.php
中有我的 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 没有按预期工作。
有什么问题吗?
正如评论中所见,问题是您没有定义应该使用什么程序来执行脚本。考虑到 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:
Using relative paths. If your cron job is executing a script of some kind, you must be sure to use only absolute paths inside that script. For example, if your script is located at /path/to/script.phpand you're trying to open a file called file.php in the same directory, you cannot use a relative path such as fopen(file.php). The file must be called from its absolute path, like this: fopen(/path/to/file.php). This is because cron jobs do not necessarily run from the directory in which the script is located, so all paths must be called specifically.
另外,我知道你想 运行 每分钟都这样。如果是这样,1 * * * *
就不行了。相反,它将 运行 at every 1st minute past every hour。所以如果你想每分钟 运行 它,说 * * * * *
.
了解 "login shell" 和 "interactive shell" 它们的含义很重要。
- 登录 shell:当您使用 ssh 会话登录并获得一个终端 window 时,您可以在其中输入 shell 命令。登录后系统会执行一些文件(.bashrc)并为您设置一些环境变量,例如PATH变量。
- 交互式shell :登录系统后,您可以手动启动shell个终端。系统执行分配给您帐户的一些配置文件 (.bash_profile, .bash_login,.profile)。此文件还设置了一些环境变量并为您手动打开的 shell 会话初始化 PATH 变量。
通过 OS 启动 shell 脚本和 cron 作业不适合上述启动 shell 的方式。因此,不会执行任何系统脚本(.bashrc)或用户配置文件。这意味着我们的 PATH 变量没有被初始化。 Shell 找不到命令,因为 PATH 变量没有指向正确的位置。
这解释了为什么您的脚本在手动启动时运行成功,但在通过 crontab 启动时失败。
解法一: 使用每个 shell 命令的绝对路径,而不是仅使用脚本文件中使用的命令名称。
- 而不是 "awk" 使用“/usr/bin/awk”
- 而不是 "sed" 使用“/bin/sed”
解决方案2:在执行shell脚本之前初始化环境变量,尤其是PATH变量!
方法一,在你的dbsync.sh中添加这个header:
#!/bin/bash -l
方法二,在你的cron文件中添加bash -l:
1 * * * * bash -l /var/www/html/dbsync/dbsync.sh /var/www/html/dbsync