簡體   English   中英

PHP掛起時exec()bash腳本

[英]PHP hanging while exec() bash script

我有一些看起來像這樣的代碼行......

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開發服務器。

我相信該行的其余部分假設轉儲任何響應,以便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');

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM