11

我的程序(恰好在 Perl 中,虽然我不认为这个问题是 Perl 特有的)在程序中的一个点输出状态消息,形式为Progress: x/yywherexyy是一个数字,例如: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. 但是,如果我省略换行符,则输出缓冲区永远不会被刷新,也不会打印任何内容。

对此有什么好的解决方案?

4

5 回答 5

12

对 STDOUT 使用 autoflush:

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
于 2011-02-15T20:46:18.870 回答
4

$| = 1

在程序早期的某个地方打开输出缓冲区的自动刷新。

还可以考虑使用“\r”将光标移回行首,而不是尝试明确计算需要向后移动多少空格。

就像您说的那样,在进度计数器运行时不要打印换行符,否则您将在单独的行上打印进度而不是覆盖旧行。

于 2011-02-15T20:47:54.210 回答
3

我知道这不是你要求的,但可能更好。我遇到了同样的问题,所以与其过多地处理它,不如使用Term::ProgressBar它看起来也不错。

于 2011-02-16T05:51:20.777 回答
1

您也可以使用ANSI 转义码直接控制光标。或者你可以使用Term::ReadKey来做同样的事情。

于 2011-02-15T23:42:28.657 回答
0

我今天不得不处理类似的事情。如果您不介意重新打印整行,您可以执行以下操作:

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

"\r" 字符是一个回车符——它将光标带回到行首。这样,您打印的任何内容都会覆盖之前的进度通知文本。

于 2011-02-15T22:31:26.093 回答