当使用Php exec()执行bash脚本时,为什么Php要等待不拥有的后台作业完成?
我需要一些帮助来理解为什么会发生这种情况。我正在从命令行运行一个php脚本,它通过exec()启动一个bash脚本。在bash脚本中,我在后台创建一个进程(例如,当使用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
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会产生预期的结果呢?PHPexec(…)
为命令打开一个指向的管道,并从中读取直到关闭,将数据作为字符串返回(您不使用)
直到所有编写器都关闭了管道,管道才会关闭,所以任何以stdout形式打开管道的后台进程都会将其保持打开状态。因此,exec
会一直等待它们,认为可能会有更多的输出。这也是一件好事:五秒钟后,它会读取一条“test-script.sh COMPLETE”消息,否则该消息就会消失
当您将stdout重定向到
/dev/null
而不是后台进程时,它将不会保持管道打开,因此exec
会立即返回,因为不可能有更多的输出 后台进程仍然通过signals和stdin/stdout绑定到exec()shell,除非您nohup
使用它们。这是shell命令/stuff.sh
,它一直在等待它的子进程。这是有意义的。非常感谢。