1

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?

Eryk Sun
  • 33,190
  • 5
  • 92
  • 111
MOPO3OB
  • 383
  • 3
  • 16
  • Typically with alternate terminals, they actually use a named pipe for standard I/O in order to communicate with the terminal application. Many applications see that standard I/O is a pipe and switch to full buffering mode instead of line buffering. The Windows console, on the other hand, uses files for the ConDrv device, which is a character device, and thus applications use line buffering or no buffering when standard I/O is a console. – Eryk Sun Mar 02 '18 at 18:56
  • The Ruby interpreter may support command-line options or environment variables to control buffering when standard I/O is a pipe or disk file. – Eryk Sun Mar 02 '18 at 18:59
  • @eryksun wise edit, thank you. What would you suggest to do with buffering? – MOPO3OB Mar 02 '18 at 21:42
  • Usually the options are no buffering, line buffering (i.e. flush when LF or CRLF is written), or full buffering (e.g. a 4 KB buffer that may not flush until the process exits, if not much is written). – Eryk Sun Mar 02 '18 at 21:46
  • @eryksun thank you for your help! Basically you did answer my question! ^^ – MOPO3OB Mar 02 '18 at 23:37

1 Answers1

1

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.

user2066657
  • 444
  • 1
  • 4
  • 23
MOPO3OB
  • 383
  • 3
  • 16
  • There are lots of versions of bash available for Windows, including Windows 10's WSL bash. The presence of bash in `PATH` doesn't mean you're using a UNIX-like terminal. I think the salient difference is whether stdout is seen as a disk/pipe file or a character file. Sometimes the latter is called a tty, even on Windows even though Windows doesn't have tty/pty devices. Look for a method like `isatty`. – Eryk Sun Mar 03 '18 at 00:10
  • @eryksun you are right. Though it's kinda funny that `STDOUT.isatty` is returning *true* on Windows console and *false* on UNIX-like terminals. Anyway this is a way steadier method to rely on. Thank you, once again. – MOPO3OB Mar 03 '18 at 00:59
  • It's expected that isatty is false for UNIX-like terminals on Windows. They're forced to use named pipes for the standard handles, since Windows doesn't have UNIX pty/tty devices. – Eryk Sun Mar 03 '18 at 01:05
  • @eryksun thanks for clearing that. Updated the answer. – MOPO3OB Mar 03 '18 at 01:14