PHPGangsta - Der praktische PHP Blog

PHP Blog von PHPGangsta


Eine Progressbar in der Konsole

with 8 comments

Wer des öfteren Konsolenscripte in PHP schreibt kennt das Problem vielleicht: Das neue Admin-Script scheint wunderbar zu laufen, aber irgendwie möchte man den aktuellen Fortschritt beobachten können, denn solche Scripte laufen auch mal mehrere Minuten oder Stunden. Häufig gibt man dann bei jedem Schleifendurchlauf einen Punkt aus, sodass sich die Konsole mit Punkten füllt. Oder aber man gibt eine Laufvariable aus:

for ($i=0; $i<1000; $i++) {
    // Schleifeninhalt
    echo $i."\n";
}

Etwas professioneller sieht natürlich eine Progressbar aus, die die vergangene Zeit ausgibt, eine prozentuale Anzeige und die geschätzte Restzeit.

Das Zend Framework bietet dafür die Zend_Progressbar. Diese Komponente stellt mehrere Adapter bereit: Console, JsPush und JsPull. Hier zeige ich nur die Verwendung für die Konsole, das oben gezeigte Beispiel setzt man so um:


<?
$adapter = new Zend_ProgressBar_Adapter_Console();
$progressBar = new Zend_ProgressBar($adapter, 0, 1000);

for ($i=0; $i<1000; $i++) {
    // Schleifeninhalt
    $progressBar->update($i); // alternativ hier: $progressBar->next();
}

$progressBar->finish();

Der Konsolen-Adapter beherrscht aber noch mehr als diese einfache Ausgabe. Man kann die einzelnen Elemente (Balken, Prozentanzeige, Restzeit und Statustext) umpositionieren wie man es braucht, außerdem ist der Adapter in der Lage automatisch seinen aktuellen Fortschritt in einer Session zu speichern, sodass relativ einfach ein Neustart nach einem Abbruch möglich ist. Weitere Informationen befinden sich im Manual.

Nach kurzer Recherche findet man weitere fertige Scripte dafür, beispielsweise dieses von dealnews.com, Inc.:

<?
for($x=1; $x<=100; $x++){
    show_status($x, 100);
    usleep(100000);
}

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";
    }
}

Weitere bekannte Vertreter sind die PEAR Console_ProgessBar und die eZ Components ezcConsoleProgressbar.

Written by Michael Kliewe

Juli 4th, 2010 at 2:08 pm

8 Responses to 'Eine Progressbar in der Konsole'

Subscribe to comments with RSS or TrackBack to 'Eine Progressbar in der Konsole'.

  1. Hi,

    diese Klassen sind sicherlich den meisten bekannt. Was mich viel eher interessieren würde, und deshalb hatte ich den Artikel auch angeklickt, wäre eine Eigenimplementierung, in der man sieht, wie solch eine Anzeige realisiert wird (also die Zeichenersetzung in der Ausgabe). Bin bisweilen immer zu fau gewesen, mich durch den Zend Code zu wühlen und mir das dort anzuschauen.

    Gruß Sebastian

    Sebastian

    5 Jul 10 at 12:43

  2. @Sebastian: Guck einfach oben, die Zeile wird einfach komplett gelöscht (mit \r) und dann neu geschrieben. So bekommt man diese “Ersetzung” hin.

    Michael Kliewe

    5 Jul 10 at 14:00

  3. Nette Sache! Ich brauche das zwar im Moment nicht, aber immer gut zu wissen, dass es da was gibt.

    Hier ein kleiner Test einer “laufenden” Uhr:

    echo PHP_EOL;

    while(true) {
    echo “\r” . date(‘Y-m-d H:i:s’);
    sleep(1);
    }

    Daniel

    5 Jul 10 at 20:39

  4. Och, mit “\r” is das ja einfach… Ich hab mir mal den Quellcode (von der ZF-Implementierung) angetan und dort wird stattdessen x08 (Backspace, kA, wie man das jetzt abkürzt) so oft ausgegeben, wie Zeichen ausgegeben wurden. Das ist schon etwas umständlicher ;)

    KingCrunch

    8 Jul 10 at 14:56

  5. […] Und hier der Link zu einem kleinen Tutorial zur Zend Framework Progressbar. […]

  6. […] Started with MongoDB and PHP • 10 Dinge, über die sich Entwickler am meisten ärgern • Eine Progressbar in der Konsole • 10 Dinge über Software-Entwicklung, die man nicht an der Uni lernt • UTF-8 für alle […]

  7. […] […]

Leave a Reply

You can add images to your comment by clicking here.