当使用Php exec()执行bash脚本时,为什么Php要等待不拥有的后台作业完成?

当使用Php exec()执行bash脚本时,为什么Php要等待不拥有的后台作业完成?,php,linux,bash,shell,unix,Php,Linux,Bash,Shell,Unix,我需要一些帮助来理解为什么会发生这种情况。我正在从命令行运行一个php脚本,它通过exec()启动一个bash脚本。在bash脚本中,我在后台创建一个进程(例如,sleep5;echo“Hello”&)。我希望php启动bash脚本,然后在完成后继续。然而,php似乎在等待bash脚本启动的后台进程完成,然后再继续执行脚本的其余部分 为了演示,我将在linux shell环境中使用以下3个示例脚本: runstuff.php <?php echo "PHP running stuff.s

我需要一些帮助来理解为什么会发生这种情况。我正在从命令行运行一个php脚本,它通过exec()启动一个bash脚本。在bash脚本中,我在后台创建一个进程(例如,
sleep5;echo“Hello”&
)。我希望php启动bash脚本,然后在完成后继续。然而,php似乎在等待bash脚本启动的后台进程完成,然后再继续执行脚本的其余部分

为了演示,我将在linux shell环境中使用以下3个示例脚本:

runstuff.php

<?php

echo "PHP running stuff.sh..." . PHP_EOL;
exec('./stuff.sh &');
echo "PHP done running stuff.sh..." . PHP_EOL;
测试脚本.sh

#!/bin/bash

echo "stuff.sh running background process..."
# This can be a script or any process placed in the background
./test-script.sh &
echo "stuff.sh done"
#!/bin/bash

echo "test-script.sh waiting 5 seconds..."
sleep 5
echo "test-script.sh COMPLETE"
#!/bin/bash

echo "stuff.sh running background process..."
./test-script.sh &> /dev/null &
echo "stuff.sh done"
现在,运行
php runstuff.php
(从命令行)将“挂起”,直到test-script.sh完成,然后php继续执行脚本的其余部分。但是,直接运行
/stuff.sh
将立即返回命令行提示符,5秒后显示输出

在运行runstuff.php时,请查看进程列表,我可以看到test-script.sh不是runstuff.php或stuff的子级,stuff.sh将失效:

 5873 pts/3    Ss     0:01  \_ bash
27389 pts/3    S+     0:00  |   \_ php runstuff.php
27390 pts/3    Z+     0:00  |       \_ [stuff.sh] <defunct>


27392 pts/3    S+     0:00 /bin/bash ./stuff.sh
27393 pts/3    S+     0:00  \_ sleep 5
所以我的问题是:为什么stuff.sh在通过Php exec()执行时会挂起,而在直接运行脚本时却不会挂起?Php是否仍然以某种方式将test-script.sh识别为子进程,即使它与stuff.sh分离

此外,似乎修改stuff.sh以使用
&>/dev/null&
而不是仅使用
&
似乎可以按预期工作

修改过的内容。sh

#!/bin/bash

echo "stuff.sh running background process..."
# This can be a script or any process placed in the background
./test-script.sh &
echo "stuff.sh done"
#!/bin/bash

echo "test-script.sh waiting 5 seconds..."
sleep 5
echo "test-script.sh COMPLETE"
#!/bin/bash

echo "stuff.sh running background process..."
./test-script.sh &> /dev/null &
echo "stuff.sh done"
那么,为什么将输出重定向到/dev/null会产生预期的结果呢?

PHP
exec(…)
为命令打开一个指向的管道,并从中读取直到关闭,将数据作为字符串返回(您不使用)

直到所有编写器都关闭了管道,管道才会关闭,所以任何以stdout形式打开管道的后台进程都会将其保持打开状态。因此,
exec
会一直等待它们,认为可能会有更多的输出。这也是一件好事:五秒钟后,它会读取一条“test-script.sh COMPLETE”消息,否则该消息就会消失


当您将stdout重定向到
/dev/null
而不是后台进程时,它将不会保持管道打开,因此
exec
会立即返回,因为不可能有更多的输出

后台进程仍然通过signals和stdin/stdout绑定到exec()shell,除非您
nohup
使用它们。这是shell命令
/stuff.sh
,它一直在等待它的子进程。这是有意义的。非常感谢。