当使用Php exec()执行bash脚本时,为什么Php等待被拒绝的后台作业完成?



我可以使用一些帮助来理解为什么会发生这种情况。我从命令行运行一个php脚本,通过exec()启动一个bash脚本。在bash脚本中,我在后台创建了一个进程(例如sleep 5; 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;

stuff.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"

test-script.sh

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

现在,运行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时,stuff.sh看起来很好。

27963 pts/3    S      0:00 /bin/bash ./stuff.sh
27965 pts/3    S      0:00  _ sleep 5

所以我的问题是:为什么stuff.sh在通过Php exec()执行时挂在周围,当它不挂在直接运行脚本时?Php是否仍将test-script.sh识别为子进程,尽管它已与stuff.sh分离?

同样,修改stuff.sh使用&> /dev/null &而不是&似乎也能像预期的那样工作。

修改stuff.sh

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

PHP exec(..)为命令打开一个管道,并从中读取直到它关闭,以字符串形式返回数据(您不使用)。

管道在所有编者关闭之前不会关闭,因此任何将管道打开为标准输出的后台进程都将使其保持打开状态。因此,exec会一直等待他们,认为可能会有更多的输出。这也是一件好事:五秒钟后,它读取了一条"test-script.sh COMPLETE"消息,否则该消息将会消失。

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

最新更新