IO.putc and $stdout.sync
It’s often useful to provide some sort of output when a script is waiting for something or running a loop that take a while to complete. Instead of writing a bunch of output and running the risk of scrolling useful information off the page, I like writing out a single ‘.’ every once in a while, just to let me know the script hasn’t hung.
The problem with just writing a ’.' is that most terminals/operating systems use a feature called “buffering”. When you write to a file (or terminal/stdout) the operating system doesn’t immediately flush that output to where you are writing. It will wait until a sufficient amount of data has been written, and then flush it all out at the same time to save on resources/system calls. A single ‘.’ is nowhere near enough data to signal the OS to flush that output, so you’ll end up seeing a bunch of them all written when the loop completes, or worst yet, nothing until the script is finished. For example:
#!/usr/bin/env ruby
20.times do
putc('.')
sleep(5)
end
On first glance, you’d think this script would print 20 dots on a line, one every 5 seconds, but it doesn’t! When run, it sits there for a full minute without outputting anything, and then spits out 20 dots right before quitting. We need to turn off write buffering on $stdout by turning on sync mode:
$stdout.sync=(true) if not $stdout.sync
If you add that line to the top of the script, each dot is written to the terminal right away.
This doesnt appear to work any longer, at least not on OSX 10.6.5, any ideas if this is still possible?
November 15th, 2010 at 8:01 pm
Still works with Ruby 1.8.7 and Mac 10.6.4 for me…
November 15th, 2010 at 8:50 pm
…and 10.6.5.
Perhaps something else has messed with terminal settings, John?
November 15th, 2010 at 9:18 pm