I've managed to capture the live stdout (and stderr) of many command line tools in a few programming languages, but there are a few tools that I can't get to work. The tools are:
- 7za.exe (part of 7-Zip)
- PsExec.exe (part of Sysinternals)
The code example below prints the live progress of most command line tools (e.g. robocopy) fine. "7za.exe b" however will first run the complete benchmark and then print all stdout in one go (i.e. not live).
If the same command is run in a cmd prompt, one can see that the benchmark prints to the console during the benchmark.
I've tried flushing, sync, async, creating unbuffered output streams for the subprocess, and most of that in both C# and Python.
Nothing seems to work.
namespace ConsoleApp
{
class Program
{
static void Main()
{
var process = new System.Diagnostics.Process
{
StartInfo = new System.Diagnostics.ProcessStartInfo
{
FileName = "7za.exe",
Arguments = "b",
UseShellExecute = false,
RedirectStandardOutput = true
}
};
process.OutputDataReceived += (sender, args) => System.Console.WriteLine(args.Data);
process.Start();
process.BeginOutputReadLine();
process.WaitForExit();
}
}
}
I had a quick look thru the 7-Zip source code put didn't notice anything out of the ordinary. Here is what 7-Zip seems to roughly do:
CStdOutStream g_StdOut(stdout);
CStdOutStream &so = (g_StdStream ? *g_StdStream : g_StdOut);
CStdOutStream &so = g_StdOut;
FILE* _file = (FILE*)so;
fputs("blah", _file)
A few more things I noticed...
Running "7za.exe b" in Cygwin also prints no progress until the benchmark is complete.
ConEmu is able to print the live output, but debugging it's code and reading the documentation didn't reveal to me how it works. I think it is related to "Windows Console" (not cmd.exe) and CSRSS.