Обновить вывод командной строки - PullRequest
10 голосов
/ 15 февраля 2011

Моя программа (которая происходит на Perl, хотя я не думаю, что этот вопрос специфичен для Perl) выводит сообщения о состоянии в одной точке программы вида Progress: x/yy, где x и yy число, например: Progress: 4/38.

Я бы хотел «перезаписать» предыдущий вывод при печати нового сообщения о состоянии, чтобы я не заполнял экран сообщениями о состоянии. До сих пор я пробовал это:

my $progressString = "Progress\t$counter / " . $total . "\n";
print $progressString;
#do lots of processing, update $counter
my $i = 0;
while ($i < length($progressString)) {
    print "\b";
    ++$i;
}

Символ возврата не будет печататься, если я добавлю новую строку в $progressString. Однако, если я пропущу перевод строки, выходной буфер никогда не очищается и ничего не печатается.

Какое хорошее решение для этого?

Ответы [ 5 ]

11 голосов
/ 15 февраля 2011

Использовать автозапуск с STDOUT:

local $| = 1; # Or use IO::Handle; STDOUT->autoflush;

print 'Progress: ';
my $progressString;
while ...
{
  # remove prev progress
  print "\b" x length($progressString) if defined $progressString;
  # do lots of processing, update $counter
  $progressString = "$counter / $total"; # No more newline
  print $progressString; # Will print, because auto-flush is on
  # end of processing
}
print "\n"; # Don't forget the trailing newline
3 голосов
/ 16 февраля 2011

Я знаю, что это не совсем то, что вы просили, но, возможно, лучше. Я столкнулся с этой же проблемой, и поэтому вместо того, чтобы заниматься ею слишком много, я использовал Term::ProgressBar, что тоже выглядит неплохо.

3 голосов
/ 15 февраля 2011

Скажите

$| = 1

где-нибудь в начале вашей программы, чтобы включить автоматическую очистку для буфера вывода.

Также рассмотрите возможность использования \ r для перемещения курсора назад к началустроки, вместо того, чтобы пытаться явно подсчитать, сколько пробелов нужно переместить назад.

Как вы сказали, не выводите новую строку, пока работает счетчик прогресса, иначе вы распечатаете свой прогресс наотдельной строкой вместо перезаписи старой.

1 голос
/ 16 февраля 2011

Вы также можете использовать управляющие коды ANSI для прямого управления курсором.Или вы можете использовать Term :: ReadKey , чтобы сделать то же самое.

0 голосов
/ 16 февраля 2011

Мне пришлось сегодня заняться чем-то похожим на это. Если вы не против перепечатать всю строку, вы можете сделать что-то вроде этого:

print "\n";
while (...) {
     print "\rProgress: $counter / $total";
     # do processing work here
     $counter++;
}
print "\n";

Символ "\ r" является возвратом каретки - он возвращает курсор назад к началу строки. Таким образом, все, что вы распечатываете, переписывает текст предыдущего уведомления о прогрессе.

...