23

I've run command line programs that output a line, and then update that line a moment later. But with ruby I can only seem to output a line and then another line.

What I have being output now:

Downloading file:
11MB 294K/s
12MB 307K/s
14MB 294K/s
15MB 301K/s
16MB 300K/s
Done!

And instead, I want to see this:

Downloading file:
11MB 294K/s

Followed a moment later by this:

Downloading file:
16MB 300K/s
Done!

The line my ruby script outputs that shows the downloaded filesize and transfer speed would be overwritten each time instead of listing the updated values as a whole new line.

I'm currently using puts to generate output, which clearly isn't designed for this case. Is there a different output method that can achieve this result?

Alex Wayne
  • 178,991
  • 47
  • 309
  • 337

1 Answers1

42

Use \r to move the cursor to the beginning of the line. And you should not be using puts as it adds \n, use print instead. Like this:

print "11MB 294K/s"
print "\r"
print "12MB 307K/s"

One thing to keep in mind though: \r doesn't delete anything, it just moves the cursor back, so you would need to pad the output with spaces to overwrite the previous output (in case it was longer).

By default when \n is printed to the standard output the buffer is flushed. Now you might need to use STDOUT.flush after print to make sure the text get printed right away.

detunized
  • 15,059
  • 3
  • 48
  • 64
  • 1
    This solution doesn't show output until either a newline is output, or the program ends, it seems. This example, for instance `print '123';sleep 5; print "\r"; print "456"` does not print anything out at first, and then prints out "456" 5 seconds later. So it doesn't help me much. – Alex Wayne Jan 21 '11 at 19:44
  • 1
    Add `STDOUT.flush` to send it to the output immediately. I updated the answer as well. – detunized Jan 21 '11 at 19:46
  • 7
    "This solution doesn't show output until either a newline is output, or the program ends" That is a deliberate design decision in OSes, to buffer writes to use the I/O channels more efficiently. Sometimes we need the data to write immediately, hence the ability to force a flush using `flush`. A better solution for an application like yours which wants all STDOUTs written immediately, is to use `STDOUT.sync = true`. Buffering will be disabled for STDOUT removing the need to use `flush`. If you want to reenable buffering, set that back to `false`. – the Tin Man Jan 21 '11 at 20:09