2015-01-02 151 views
4

我有一些代码,看起来像这样...PHP悬而执行exec()bash脚本

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

$this->path是一个shell脚本,开始是一个参数的shell脚本,我相信剩下的的行是假设转储任何响应,所以php脚本可以继续运行。它不像它应该那样工作,PHP正在成功启动shell脚本(启动游戏服务器),但PHP只是挂起,直到我使用shell关闭服务器。当我用shell关闭服务器时,它完成执行并收到'命令执行'响应。我也禁用了SELinux的执行,以确保它不会产生干扰。运行Linux - Fedora 21和内置的PHP开发服务器。

回答

0

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

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

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

希望帮助: )

+0

不幸的是这并没有为我工作:(。 – slick1537

+0

你得到了相同的行为? –

+0

是完全一样的。 – slick1537

0

一个不同的(难看的)方法是在屏幕会话中实际运行你的shell脚本。

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

相信该行的其余部分是假设转储任何反应,使PHP脚本可以继续运行

如果你不明白,这里是解释。如果你有:

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

> /dev/null部分意味着重定向标准输出(即,由该命令所产生的规则输出)到/ 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 &'); 
+0

我去''set -m &&'部分添加了我的代码。当通过shell执行时'jobs'返回一行'done'。该脚本只是创建自己的进程然后退出当我通过PHP执行该行时,我得到的结果与往常一样,'jobs'完全不返回任何东西。只是为了清楚shell脚本始终成功执行,但当通过PHP完成它挂起php。 – slick1537

+0

也checkjobs行返回'shopt -u checkjobs' – slick1537

+0

尝试删除'>/dev/null 2>&1&'部分并通过PHP执行它,看看是否有任何输出。这可能是一个权限问题或其他导致PHP挂起而不是命令行的东西。 – Mike