如何进行无阻塞的php exec调用?

时间:2019-05-26 17:57:15

标签: php bash

我需要在Linux中将文本回显到命名管道(FIFO)。即使我在后台运行'&'并将所有输出重定向到/ dev / null,shell_exec调用始终会阻塞。

整个互联网上都有很多关于这个问题的答案,它们基本上都指向以下php手册部分:

  

如果使用此功能启动程序,则要使其在后台继续运行,必须将程序的输出重定向到文件或其他输出流。否则,PHP会挂起,直到程序执行结束。

可以肯定的是,当我尝试使用其他命令(如sleep)进行非阻塞方法(后台运行并重定向到/ dev / null)时,php成功执行而没有挂起。但是对于回显FIFO的情况,即使使用bash运行相同的命令也不会产生可见的输出并立即返回到shell,php仍会挂起。

在bash中,我可以运行:

bash$ { echo yay > fifo & } &> /dev/null
bash$ cat fifo
yay
[1]+  Done                    echo yay > fifo

但是在使用php echo.php运行以下php文件时:

<?php
shell_exec("{ echo yay > fifo & } &> /dev/null");
?>

它挂起,除非我先打开fifo进行阅读。

所以我的问题是,为什么这会阻止,但睡眠却没有呢?另外,我想知道幕后发生的事情:当我将'&'放入php调用中时,即使shell_exec调用被阻止,echo调用也显然不会阻止任何事情bash会话php调用了它,因为当我CTRL+C从php中退出时,我可以从FIFO中读取“是”(如果我不后台echo命令,则在CTRL+C之后FIFO不包含任何文本)。这表明php在进入下一条指令之前可能正在等待echo命令的pid。这是真的吗?

1 个答案:

答案 0 :(得分:1)

我一直在尝试类似的方法,最后提出了以下解决方案:

/**
 * This runs a shell command on the server under the current PHP user, that is in CLI mode it is the user you are logged in with.
 * If a command is run in the background the method will return the location of the tempfile that captures the output. In that case you will have to manually remove the temporary file.
 */
static public function command($cmd, $show_output = true, $escape_command = false, $run_in_background = false)   
{ 
  if ($escape_command)
    $cmd = escapeshellcmd($cmd);

  $f = trim(`mktemp`);
  passthru($cmd . ($show_output ? " | tee $f" : " > $f") . ($run_in_background ? ' &' : '')); 
  return $run_in_background ? $f : trim(`cat $f ; rm -rf $f`);
}

诀窍是将输出写入临时文件,并在命令完成后将其返回(阻止行为),或者仅返回文件路径(非阻止行为)。另外,我使用passthru而不是shell_exec,因为由于阻塞行为,以后无法进行交互式会话。