PHP挂起时exec()bash脚本

时间:2015-01-02 19:04:29

标签: php linux bash shell

我有一些看起来像这样的代码......

exec($this->path.' start > /dev/null 2>&1 &');
return ['status' => 'Command executed'];

$this->path是一个shell脚本,start是shell脚本的参数,我相信该行的其余部分是为了转储任何响应,因此php脚本可以继续运行。它没有像它应该的那样工作,php正在成功启动shell脚本(启动游戏服务器)但是php只是挂起,直到我使用shell关闭服务器。当我用shell关闭服务器时它完成执行并且我收到'命令执行'响应。我也禁用了SELinux的执行,以确保它不会干扰。

运行Linux - Fedora 21和内置的PHP开发服务器。

3 个答案:

答案 0 :(得分:3)

  

我相信该行的其余部分是假设转储任何响应,以便php脚本可以继续运行

如果您不理解,请在此解释。如果你有:

exec($this->path.' start > /dev/null 2>&1 &');

> /dev/null部分意味着将stdout(即命令生成的常规输出)重定向到/ dev / null(这是空设备)。因此,命令本身产生的任何输出都将被抑制。

2>&1部分意味着将stderror(即执行命令产生的任何错误)重定向到stdout。但是,由于stdout被重定向到/ dev / null,因此任何错误也将被重定向到那里。因此,使用这两个,它会抑制命令将产生的任何消息。

最后,&(&符号)最后将命令分配给新进程。来自Bash man page

  

如果命令由控制操作员&,shell终止   在子shell中在后台执行命令。外壳确实如此   不等待命令完成,返回状态为0(true)。

但是,根据this question,你正在做什么应该正在运作。必须有其他事情来阻止该过程成功分叉。只是为了排除PHP的问题,我首先尝试通过命令行而不是PHP的exec执行命令。如果它仍然无法正常工作,我会猜测它是因为您的Job Control存在问题。它要么以某种方式被禁用。我还没有在PHP中尝试过这个,但您可以使用set -m命令(启用作业控制)启用它。请注意,要禁用作业控制而不是set -m,请执行set +m。以下是如何在PHP中执行此操作:

exec('set -m && ' . $this->path.' start > /dev/null 2>&1 &');

您可以做的另一件事是在PHP脚本执行时,登录命令行并输入命令jobs并查看其输出。如果它是空白的,PHP不会正确分配作业。你应该看到类似的东西:

[1]+  Stopped                 your_command.sh

请注意这里的stopped。如果进程仍在运行,那么这可能不应该是stopped

您可以做的另一件事是查看是否启用了checkjobs。登录服务器并执行以下命令以获取内置shell optional behavior

shopt -p | grep checkjobs

如果输出为shopt -u checkjobs,则不是问题所在。如果它改为shopt -s checkjobs,这可能会导致您看到的行为,因为使用后台作业查杀shell将导致错误,表明有作业正在运行,而您实际上必须杀死shell 两次摆脱它。也许这是PHP开发人员没有考虑的事情。在这种情况下,在PHP命令之前添加shopt -u checkjobs &&

exec('shopt -u checkjobs && ' . $this->path.' start > /dev/null 2>&1 &');

答案 1 :(得分:0)

我在生产环境中解决了同样的问题,如下所示:

pclose(popen($this->path.' start > /dev/null 2>&1 &', 'r'));

因此,诀窍是启动服务器,然后关闭进程文件指针

希望有所帮助:)

答案 2 :(得分:0)

一种不同(丑陋)的方法是在屏幕会话中实际运行shell脚本。

exec('screen -dmS -X ' . $this->path . ' start');