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.