PHP悬挂exec()bash脚本

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

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

$this->path是一个shell脚本,start是shell脚本的一个参数,我相信该行的其余部分是假设转储任何响应,以便php脚本可以继续运行。 它不是像它应该的工作,PHP是成功地启动shell脚本(启动游戏服务器),但PHP只是挂起,直到我closures服务器使用shell。 当我用shellclosures服务器时,它完成执行,并收到“命令执行”响应。 我也禁用了SELinux的执行,以确保它不会干扰。

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

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

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

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

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

2>&1部分表示将stderror(即执行命令产生的任何错误)重定向到stdout。 但是,由于stdout被重定向到/ dev / null,任何错误也将被重定向到那里。 因此,在这两种情况下,它会压制命令所产生的任何信息。

最后, & (&符号)最后将命令分配给一个新的进程。 从Bash手册页 :

如果一个命令被控制操作符&终止,那么shell在一个子shell中在后台执行命令。 shell不会等待命令完成,返回状态为0(true)。

但是,根据这个问题 ,你在做什么应该是工作。 必须有其他的事情来阻止这个过程成功分叉。 只是为了排除PHP的问题,我首先尝试通过命令行执行命令,而不是通过PHP的exec。 如果它仍然不起作用,我想这是因为你的工作控制有问题。 要么它以某种方式被禁用。 我还没有在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可选行为 :

 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 &'); 

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

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

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

希望帮助:)

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

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