简体   繁体   English

使用Php exec()执行bash脚本时,为什么Php会等待不相关的后台作业完成?

[英]When executing a bash script with Php exec(), why does Php wait for disowned background jobs to complete?

I could use some help understanding why this is happening. 我可以用一些帮助来理解为什么会这样。 I am running a php script from command line that launches a bash script via exec(). 我从命令行运行php脚本,通过exec()启动bash脚本。 In the bash script, I'm creating a process in the background (eg sleep 5; echo "Hello" & ). 在bash脚本中,我在后台创建一个进程(例如sleep 5; echo "Hello" & )。 I am expecting php to launch the bash script and then move on once it's done. 我期待php启动bash脚本,然后一旦完成就继续前进。 However, php seems to be waiting for the background process launched by the bash script to complete before progressing through the rest of the script 但是,php似乎正在等待bash脚本启动的后台进程在完成脚本的其余部分之前完成

To demonstrate, I'll use the following 3 example scripts in a linux shell environment: 为了演示,我将在linux shell环境中使用以下3个示例脚本:

runstuff.php runstuff.php

<?php

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

stuff.sh 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 test-script.sh

#!/bin/bash

echo "test-script.sh waiting 5 seconds..."
sleep 5
echo "test-script.sh COMPLETE"

Now, running php runstuff.php (from the command line) will "hang" until test-script.sh completes and then php progresses through the rest of the script. 现在,运行php runstuff.php (从命令行)将“挂起”,直到test-script.sh完成,然后php继续执行脚本的其余部分。 However, running ./stuff.sh directly will immediately return to the command line prompt and the output appears 5 seconds later. 但是,直接运行./stuff.sh将立即返回到命令行提示符,输出将在5秒后出现。

Look at the process list when running runstuff.php, I can see that test-script.sh is NOT a child of either runstuff.php or stuff and stuff.sh goes defunct: 运行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

When running ./stuff.sh directly, stuff.sh looks fine. 直接运行./stuff.sh ,stuff.sh看起来很好。

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

So my question is this: Why is stuff.sh hanging around when executed through Php exec() when it doesn't hang around when running the script directly? 所以我的问题是这样的:为什么在通过Php exec()执行时,stuff.sh会在直接运行脚本时不会挂起? Is Php somehow still recognizing test-script.sh as a child process even though it's detached from stuff.sh? 是不是Php仍然认为test-script.sh是一个子进程,即使它与stuff.sh分离了?

Also, it seems that modifying stuff.sh to use &> /dev/null & instead of just & seems to work as expected. 此外,似乎修改stuff.sh使用&> /dev/null &而不仅仅是&似乎按预期工作。

modified stuff.sh 修改的stuff.sh

#!/bin/bash

echo "stuff.sh running background process..."
./test-script.sh &> /dev/null &
echo "stuff.sh done"

So why does redirecting output to /dev/null produce the expected results? 那么为什么将输出重定向到/ dev / null会产生预期的结果呢?

PHP exec(..) opens a pipe to for the command, and reads from it until it closes, returning the data as a string (which you don't use). PHP exec(..)为命令打开一个管道,并从中读取直到它关闭,将数据作为字符串返回(您不使用它)。

Pipes don't close until all writers have closed it, so any background process with the pipe open as stdout will keep it open. 管道在所有编写器都关闭之前不会关闭,因此管道打开为stdout的任何后台进程都会保持打开状态。 Therefore, exec will keep waiting for them, thinking there may be more output. 因此, exec将继续等待他们,认为可能会有更多的输出。 It's a good thing too: five seconds later, it reads a "test-script.sh COMPLETE" message which would otherwise have disappeared. 这也是一件好事:五秒钟之后,它会读取一条“test-script.sh COMPLETE”消息,否则消息就会消失。

When you redirect stdout to /dev/null instead for the background process, it will not keep the pipe open, and exec therefore returns immediately since there can't possibly be any more output. 当你将stdout重定向到/dev/null而不是后台进程时,它不会保持管道打开,因此exec会立即返回,因为不可能再有输出。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM