有没有一种方法可以使用shell_exec而无需等待命令完成?


95

我有一个过程密集型任务,我想在后台运行。

用户单击页面,运行PHP脚本,最后,根据需要,根据某些条件,它必须运行shell脚本EG:

shell_exec('php measurePerformance.php 47 844 email@yahoo.com');

当前,我使用shell_exec但这需要脚本等待输出。有什么方法可以执行我想要的命令,而无需等待命令完成?


注意:该过程必须立即开始,因此不能选择cron。
ToughPal

2
简要说明:确保该页面不会被所有人(搜索引擎/欺诈性用户)访问,并且如果您处于共享环境中,则所有脚本(尤其是php!)的执行时间可能会受到限制。无论如何,您可能要看一下set_time_limit / php.ini。
merkuro

Answers:


150

如何添加。

"> /dev/null 2>/dev/null &"

shell_exec('php measurePerformance.php 47 844 email@yahoo.com > /dev/null 2>/dev/null &');

请注意,这也摆脱了stdio和stderr。


2
不,没有副作用。如果你的某个时候决定要标准输入输出或者过程的stderr输出考虑stackoverflow.com/questions/45953/...
抖动

1
问题:那只是丢弃输出,对吧?PHP是否仍然等待该过程完成才继续执行,还是会被触发而忘记?
艾伦·斯托姆

5
是的,丢弃。是的,忘却了
抖动2009年

3
注意:> /dev/null 2>&1 &从其他答案中可以看出,> /dev/null 2>/dev/null &此处给出的是简洁形式。这基本上是说“将STDERR(2)重定向到与STDOUT(&1)相同的位置”。
rymo

3
我通常通过添加echo $!得到运行脚本的PID。>> /tmp/pid.txt在exec命令的末尾,但是通过将输出和错误重定向到/ dev / null,不再有pid文件:你们中的任何人都可以在不等待输出的情况下获取exec启动的脚本的PID吗?
hugsbrugs '16

28

这将执行命令并与正在运行的进程断开连接。当然,它可以是您想要的任何命令。但是对于测试,您可以使用sleep(20)命令创建一个php文件。

exec("nohup /usr/bin/php -f sleep.php > /dev/null 2>&1 &");

这个还是shell_exec更好?
realtebo 2015年

嗨,我可以使用此shell_exec(“ nohup / usr / bin / php -f example.com/notifications/sendnotifications_async > / dev / null 2>&1&”)运行函数吗?
Waseem Bashir

为什么 nohup&
bugmenot123 '19

11

您还可以立即将输出返回给客户端,然后继续处理您的PHP代码。

这是我用于长时间等待的Ajax调用的方法,这对客户端没有任何影响:

ob_end_clean();
ignore_user_abort();
ob_start();
header("Connection: close");
echo json_encode($out);
header("Content-Length: " . ob_get_length());
ob_end_flush();
flush();
// execute your command here. client will not wait for response, it already has one above.

您可以在这里找到详细的解释:http : //oytun.co/response-now-process-later


1
行动...我在这里醒来一个僵尸问题,我还没有意识到。但是,这些信息可能对其他人有利。
Oytun

3
这与shell_exec 无关
bugmenot123 '19

8

在Windows 2003上,无需等待即可调用另一个脚本,我使用了以下命令:

$commandString = "start /b c:\\php\\php.EXE C:\\Inetpub\\wwwroot\\mysite.com\\phpforktest.php --passmsg=$testmsg"; 
pclose(popen($commandString, 'r'));

这仅在授予更改权限后才起作用cmd.exe-添加“读取”和“执行” IUSR_YOURMACHINE(我还将写入设置为“拒绝”)。


7

当然可以,windows您可以使用:

$WshShell = new COM("WScript.Shell");
$oExec = $WshShell->Run("C:/path/to/php-win.exe -f C:/path/to/script.php", 0, false);

注意:

如果遇到COM错误,请将扩展名添加到您的扩展名php.ini并重新启动apache

[COM_DOT_NET]
extension=php_com_dotnet.dll

我不知道,但是对我有用。请任何人解释wscript.shell是什么,它做什么。
GeekWithGlasses

您能解释一下为什么这行没有输出吗?`$ oExec = $ WshShell->运行('C:\ Users \ Shreyash \ Desktop \ phantomjs-2.1.1-windows \ bin \ phantomjs.exe -f C:\ xampp \ htdocs \ composer \ test_0.js',0 ,false);`
GeekWithGlasses

您可能在test_0.js上出错,请检查幻像日志。
CONvid19

6

使用PHP的popen命令,例如:

pclose(popen("start c:\wamp\bin\php.exe c:\wamp\www\script.php","r"));

这将创建一个子进程,脚本将在后台执行,而无需等待输出。


4
它等待子进程结束。至少在获胜时
Max Chernopolsky '16

此处的背景是借助Windows“启动”命令实现的,该命令以您要运行的exe前缀为前缀,如果您省略它,它将无法正常工作,而且我不希望它可以在其他OS上工作……但是它确实可以为我工作,谢谢!:-)
安东尼

1

如果它不在网页上,我建议生成某种信号(也许将文件放在目录中),并进行cron作业来接管需要完成的工作。否则,我们很可能会进入Apache进程内部的使用pcntl_fork()和开发领域exec(),这简直是不好的mojo。


1
你说的不好 你能详细说明一下吗?
Mayank

1

那会起作用,但是您必须小心不要使服务器过载,因为每次调用此函数都会在后台运行时,它将创建一个新进程。如果同时只有一个并发呼叫,则此替代方法将完成此工作。

如果没有,我建议运行一个消息队列,例如beantalkd / gearman / amazon sqs。

By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.