我的程序(碰巧在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
中添加换行符,则不会打印退格符。但是,如果我省略换行符,则不会刷新输出缓冲区,也不会打印任何内容。
对此有什么好的解决方案?
答案 0 :(得分:11)
对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
答案 1 :(得分:3)
说
$| = 1
在程序的早期某个地方为输出缓冲区打开autoflushing。
还可以考虑使用“\ r”将光标移回到行的开头,而不是尝试显式计算需要移回的空格数。
就像你说的那样,不要在进度计数器运行时打印换行符,否则你将在单独的行上打印出你的进度而不是覆盖旧行。
答案 2 :(得分:3)
我知道这不是你要求的,但可能更好。我碰巧遇到了同样的问题,所以不要过多地使用它Term::ProgressBar
,看起来也不错。
答案 3 :(得分:1)
您也可以使用ANSI escape codes直接控制光标。或者您可以使用Term::ReadKey执行相同的操作。
答案 4 :(得分:0)
今天我必须解决与此类似的问题。 如果你不介意重印整行,你可以这样做:
print "\n";
while (...) {
print "\rProgress: $counter / $total";
# do processing work here
$counter++;
}
print "\n";
“\ r”字符是一个回车符 - 它将光标带回到行的开头。这样,您打印的任何内容都会覆盖先前的进度通知文本。