12

Hi according to this post, unbuffer connects to a command via a pseudo-terminal (pty), which makes the system treat it as an interactive process, therefore not using any stdout buffering.

I would like to use this function on Windows. May I know what is the equivalent of unbuffer program on Windows? Thanks.

Community
  • 1
  • 1
userpal
  • 1,483
  • 2
  • 22
  • 38
  • There is no equivalent. Windows doesn't have pseudo-terminals. – Harry Johnston Jul 17 '12 at 22:46
  • @HarryJohnston Hi Harry, I would like to use Java to execute external commands and read the stdout output `in real time`. Some .exe program are giving me problem because of stdout buffering. I could not get any stdout output when the program is still running. When the program is terminated, I suddenly get a lot of stdout output. (This program is able to generate real time stdout output when I run it manually in command prompt window) How can I solve this problem if there is no pseudo terminal in Windows? – userpal Jul 18 '12 at 04:04
  • It isn't the operating system that does the buffering, it's the application. You'll need to fix the .exe program(s) in question so that they don't buffer their output. – Harry Johnston Jul 18 '12 at 04:16
  • @HarryJohnston When I run the .exe program in command prompt, it is working fine and showing stdout every 1 second. The problem only happens when I try to run the program from Java. If I don't have access to the .exe program source code, is there any way that I can make my Java program run the program just like a command prompt window and get the stdout output in real time? Thanks. – userpal Jul 18 '12 at 05:04
  • If you do `a.exe | more` is the output buffered? – Harry Johnston Jul 18 '12 at 05:13
  • When I run `a.exe|more`, I could not see the stdout printed on the screen. When I use `Ctrl-C`, no stdout output is shown. When I run `a.exe > stdout.out 2> stderr.err`, if I open the file `stdout.out` when `a.exe` is still running, the file is empty. When I terminate the program using `Ctrl-C`, I found that `stdout.out` is suddenly filled with many stdout output. – userpal Jul 18 '12 at 05:57
  • @HarryJohnston When I run `a.exe|more`, I could not see the stdout printed on the screen. When I press `Ctrl-C`, no stdout output is shown. When I run `a.exe > stdout.out 2> stderr.err`, if I open the file `stdout.out` when `a.exe` is still running, the file is empty. When I terminate the program using `Ctrl-C`, I found that `stdout.out` is suddenly filled with many stdout output. – userpal Jul 18 '12 at 06:20

3 Answers3

11

I spent some time on this and succeeded. I found this blog during research, and decided to return and provide my solution to save the next guy some time. I'm responding as a guest with a false email so I won't be interacting, but no further information should be required.

On Jul 18 '12 at 19:41 Harry Johnston wrote:

"In principle, if you know how much data to expect, you could use the console API functions to create a console for the application to write to, and then read the output from the console. But you can't do that from Java, you would need to write a C application to do it for you."

Thing is, there is already a utility that does this. It's written for a slightly different use, but it can be coxed into providing the desired result. Its intended purpose is to enable a windows console app to interact with a Linux style tty terminal. It does this by running a hidden console and accesses the console buffer directly. If you tried to use it – you'd fail. I got lucky and discovered that there are undocumented switches for this utility which will allow it to provide simple unbuffered output. Without the switches it fails with the error – the output is not a tty – when trying to pipe output.

The utility is called winpty. You can get it here:

https://github.com/rprichard/winpty/releases

The undocumented switches are mentioned here:

https://github.com/rprichard/winpty/issues/103

I’m using the MSYS2 version. You’ll need the msys-2.0.dll to use it.

Simply run:

winpty.exe -Xallow-non-tty -Xplain your_program.exe | receive_unbuffered_output.exe

-Xallow-non-tty , will allow piped output

-Xplain , will remove the added Linux terminal escape codes (or whatever they’re called)

Required files are:

winpty.exe
winpty-agent.exe
winpty.dll
msys-2.0.dll

winpty-debugserver.exe – Not needed

Jean-François Fabre
  • 137,073
  • 23
  • 153
  • 219
noname
  • 111
  • 1
  • 3
5

The behaviour you're describing is typical of applications using run-time libraries for I/O. By default, most runtime libraries check to see whether the handle is a character mode device such as a console, and if so, they don't do any buffering. (Ideally the run-time library would treat a pipe in the same way as a console, but it seems that most don't.)

I'm not aware of any sensible way to trick such an application into thinking it is writing to a console when it is actually writing to a pipe.

Addendum: seven years later, Windows finally supports pseudoconsoles. If you are running on Windows 10 v1809 or later, this new API should solve your problem.

On older versions of Windows, if you know how much data to expect, you could in principle use the console API functions to create a console for the application to write to, and then read the output from the console. But you can't do that from Java, you would need to write a C application to do it for you.

Similarly, in principle it should presumably be possible to write a device driver equivalent to a Unix pseudo-terminal, one that acts like a pipe but reports itself to be a character-mode device. But writing device drivers requires specific expertise, and they have to be digitally signed, so unless there is an existing product out there this approach isn't likely to be feasible.

Harry Johnston
  • 35,639
  • 6
  • 68
  • 158
  • One existing option may be the [com0com](http://com0com.sourceforge.net/) null-modem emulator. (If I remember correctly, serial ports are usually treated as unbuffered.) – Harry Johnston Oct 07 '17 at 07:31
2

Disclaimer: My answer only deals with executables compiled using MSVC.

The buffering policy is coded inside Microsoft C Runtime (CRT) Library. You can learn the details here. This article suggests using console handles and manipulate console buffers to receive unbuffered output.

However, there's an undocumented feature inside Microsoft C Runtime to inherit file handles with some internal flags directly from its parent process using lpReserved2 and cbReserved2 fields of STARTUPINFO structure. You can find the details in the crt source code provided by Microsoft Visual Studio. Or search for something like posfhnd on GitHub.

We can exploit this undocumented feature to provide a pipe handle and specify FOPEN | FDEV flags to the child process, to fool the child process treat that pipe handle the same way as a FILE_TYPE_CHAR handle.

I have a working Python3 script to demonstrate this method.

youfu
  • 1,547
  • 3
  • 15
  • 21