让PHP用shell命令返回的每一行进行更新


Get PHP to update with every line returned from a shell command

背景:我正在尝试使用php编写一个shell脚本,该脚本将自动签出几个大型SVN repo。我还使用PEAR控制台进度条类来显示签出的进度(这不是完全必要的,但这正是我提出问题的原因(。

问题:有没有一种方法可以运行一个循环,它会随着命令行上STDIN的每一行输出而更新?

如果我做

<?php shell_exec("svn co svn://my.repo.com/repo/trunk"); ?>

我用一个巨大的字符串返回命令的所有输出。尝试类似的循环

   <?php     $bar = new Console_ProgressBar('%fraction% [%bar%] %percent% | %elapsed% :: %estimate%', '=>', ' ', 80, $total);
    $bar->display(0);
    stream_set_blocking(STDIN, 0);
    $output = array();
    $return = '';
    exec("svn co $svnUrl $folder", $output, $return);
    while (!isset($return))
    {
        $bar->update(count($output));
    }
    $bar->erase(); ?>

将显示栏,但不会更新。

有什么解决方案吗?

==========================更新=========================

以下是我根据答案得出的工作代码(供将来参考(:

    <?php    
    $bar = new Console_ProgressBar('%fraction% [%bar%] %percent% | %elapsed% :: %estimate%', '=>', ' ', 80, $total);
    $handle = popen("/usr/bin/svn co $svnUrl $folder", 'r');
    $elapsed = 0;
    $bar->display($elapsed);
    while ($line = fgets($handle))
    {
        $elapsed++;
        $bar->update($elapsed);
    }
    pclose($handle);
    ?>

PHP不是多线程的。exec((和company将阻止您的脚本,直到exec的任务完成。使用while((循环毫无意义,因为在svn调用完成之前,循环甚至不会开始运行。

如果你想运行多个并行svn,你需要使用popen(((或proc_open(((,它为你提供了一个文件句柄,你可以从中读取外部命令的输出,并同时拥有多个这样的外部命令。

使用输出缓冲

参见:

  • http://php.net/manual/en/function.ob-start.php
  • http://php.net/manual/en/function.ob-flush.php
  • http://php.net/manual/en/function.ob-end-clean.php

并查看一些相关信息:

  • PHP命令行上的输出缓冲
  • Kohana 3命令行输出缓冲

AS我理解php同步执行脚本的问题。这意味着循环将只在exec命令之后运行,并且输出将不会更改,因为它已经完成了。尝试使用fork.