我目前正在尝试向命令行脚本添加进度条,我尝试了各种解决方案(包括Zend和Console_ProgressBar).它们两者有共同的问题是进度条不会粘在窗口的底部,因为在脚本中,输出新行和其他信息.
有没有办法让进度条保持在终端的底部,但仍然能够在脚本运行时输出其他信息?
[编辑]
我想到了:
而不是直接输出到STDOUT我实际上是抓取变量内的输出,我擦除屏幕echo chr(27) . '[2J'
然后输出到STDOUT变量的内容然后追加我的进度条.
希望有道理:)
这是cli很好的进度条:
http://snipplr.com/view/29548/
* for($x=1;$x<=100;$x++){ * * show_status($x, 100); * * usleep(100000); * * } * * * @param int $done how many items are completed * @param int $total how many items are to be done total * @param int $size optional size of the status bar * @return void * */ function show_status($done, $total, $size=30) { static $start_time; // if we go over our bound, just ignore it if($done > $total) return; if(empty($start_time)) $start_time=time(); $now = time(); $perc=(double)($done/$total); $bar=floor($perc*$size); $status_bar="\r["; $status_bar.=str_repeat("=", $bar); if($bar<$size){ $status_bar.=">"; $status_bar.=str_repeat(" ", $size-$bar); } else { $status_bar.="="; } $disp=number_format($perc*100, 0); $status_bar.="] $disp% $done/$total"; $rate = ($now-$start_time)/$done; $left = $total - $done; $eta = round($rate * $left, 2); $elapsed = $now - $start_time; $status_bar.= " remaining: ".number_format($eta)." sec. elapsed: ".number_format($elapsed)." sec."; echo "$status_bar "; flush(); // when done, send a newline if($done == $total) { echo "\n"; } } ?>
其他答案似乎过于复杂.我的解决方案是在下次更新之前简单地回显\ 033 [0G转义序列,它将光标移回到开头.
function progressBar($done, $total) { $perc = floor(($done / $total) * 100); $left = 100 - $perc; $write = sprintf("\033[0G\033[2K[%'={$perc}s>%-{$left}s] - $perc%% - $done/$total", "", ""); fwrite(STDERR, $write); }
首次调用该函数会输出进度条,每次后续调用都会用新的进度条覆盖最后一行.
编辑:我已经改变了回显\ r到转义序列\ 033 [0G,现在这应该适用于OSX以及Linux/Unix.
编辑2:根据@tbjers建议修正了第3行可能出现的错误.
编辑3:更新了新版本,打印到STDERR,现在也在GitHub上:https://github.com/MacroMan/PHPTerminalProgressBar