我有一些看起来像这样的代码行…
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');