Search code examples
rubywindowscygwinmingwwindows-console

Ruby's output in the Windows console VS mingw64 VS cygwin64


I'm having a really weird problem here. Here's simple code that uses puts:

puts "Dale"
sleep 1
puts "Cooper"

I have 3 different terminals/consoles:

  • Windows console (system default)
  • mingw64 (UNIX-like terminal that was installed alongside with Git)
  • cygwin64 (UNIX-like terminal)

Here is weird thing: the code runs as expected only in the standard Windows console. UNIX-like terminals are waiting for 1 second and only then showing output (both lines at the same moment). Basically, UNIX-like terminals are waiting for the program to exit, and then they are showing the final result of output.

If I replace puts with print, it wont affect the execution process. UNIX-like terminals will still delay output until the program quits.

But the next two examples work right in all 3 terminals/consoles:

system("echo Dale")
sleep 1
system("echo Cooper")

This one adds quotes, but aside from this, the code works as expected.

p "Dale"
sleep 1
p "Cooper"

Having said this, I assume this has something to do with Ruby. I have tried different versions of Ruby.

Can someone explain why this is happening and what are possible ways to bypass this issue?


Solution

  • Here's me answering my own question.

    Little background

    If you do puts STDOUT.sync before the code then you will see that no matter if you are using Windows console or UNIX-like terminal, it will say that STDOUT.sync is set to false. That's weird thing because Windows console is flushing output immediately and UNIX-like terminals don't. I'm not sure why that's happening.

    Solution

    You can do STDOUT.flush (or $stdout.flush) to flush buffer or you can set STDOUT.sync (or $stdout.sync) to true. Both variants are completely friendly with Windows console. So the code will be as following:

    puts "Dale"
    STDOUT.flush
    sleep 1
    puts "Cooper"
    

    or more recommended:

    STDOUT.sync = true
    puts "Dale"
    sleep 1
    puts "Cooper"
    

    Determining whenever it's Windows console or UNIX-like terminal

    Here is a little trick suggested by @eryksun to know if code is being run in Windows console or UNIX-like terminal. STDOUT.isatty works kind of inverted when run under Windows, but nevertheless it does the trick.

    if STDOUT.isatty
        # Windows console
    else
        # UNIX-like terminal
    end
    

    Keep in mind that this assumes that you already know that the code is being run under Windows. A good way to check OS is described here.

    References

    Major source for the answer can be found here. Idea for the answer belongs to @eryksun.

    STDOUT.sync, STDOUT.sync = (question about this method), STDOUT.flush, STDOUT.isatty.