In windows, can I redirect stdout to a (named) pipe in command line?
Solution 1
I'm not sure why you don't want to redirect to a file. There are two methods I will provide here. One method is to redirect to and read from a file, the other is a set of programs.
Named pipes
What I did was write two programs for .NET 4. One sends output to a named pipe, the other reads from this pipe and displays to the console. Usage is quite simple:
asdf.exe | NamedPipeServer.exe "APipeName"
In another console window:
NamedPipeClient.exe "APipeName"
Unfortunately, this can only redirect stdout
(or stdin
, or combined), not stderr
by itself, due to limitations in the pipe operator (|
) in the Windows Command Prompt. If you figure out how to send stderr
through that pipe operator, it should work. Alternatively, the server could be modified to launch your program and specifically redirect stderr
. If that is necessary, let me know in a comment (or do it yourself); it's not too difficult if you have some C# and .NET "Process" library knowledge.
You can download the server and the client.
If you close the server after connection, the client will close immediately. If you close the client after connection, the server will close as soon as you try to send something through it. It's not possible to reconnect a broken pipe, mostly because I can't be bothered doing something so complicated right now. It's also limited to one client per server.
Source code
These are written in C#. There's not much point trying to explain it. They use the .NET NamedPipeServerStream and NamedPipeClientStream.
The server:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.IO.Pipes;
using System.IO;
namespace NamedPipeServer
{
class Program
{
static void Main(string[] args)
{
if (args == null || args.Length == 0)
{
Console.Error.WriteLine("[NamedPipeServer]: Need pipe name.");
return;
}
NamedPipeServerStream PipeServer = new NamedPipeServerStream(args[0], System.IO.Pipes.PipeDirection.Out);
PipeServer.WaitForConnection();
StreamWriter PipeWriter = new StreamWriter(PipeServer);
PipeWriter.AutoFlush = true;
string tempWrite;
while ((tempWrite = Console.ReadLine()) != null)
{
try
{
PipeWriter.WriteLine(tempWrite);
}
catch (IOException ex)
{
if (ex.Message == "Pipe is broken.")
{
Console.Error.WriteLine("[NamedPipeServer]: NamedPipeClient was closed, exiting");
return;
}
}
}
PipeWriter.Close();
PipeServer.Close();
}
}
}
The client:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.IO.Pipes;
using System.IO;
namespace NamedPipeClient
{
class Program
{
static void Main(string[] args)
{
if (args == null || args.Length == 0)
{
Console.Error.WriteLine("[NamedPipeClient]: Need pipe name.");
return;
}
NamedPipeClientStream PipeClient = new NamedPipeClientStream(".", args[0], System.IO.Pipes.PipeDirection.In);
PipeClient.Connect();
StreamReader PipeReader = new StreamReader(PipeClient);
string tempRead;
while ((tempRead = PipeReader.ReadLine()) != null)
{
Console.WriteLine(tempRead);
}
PipeReader.Close();
PipeClient.Close();
}
}
}
Redirecting to a file
type NUL>StdErr.temp
start powershell -c Get-Content StdErr.temp -Wait
MyExecutable.exe 2>StdErr.temp
- Create an empty file
- Start a new console window that watches the file
- Run executable and redirect
stderr
output to that file
This provides the desired effect of one console window to watch stdout
(and provide stdin
), and another to watch stderr
.
Anything that mimics tail
would work. The PowerShell method works natively in Windows, but may be a bit slow (i.e. there's some latency between the writing to the file and the displaying to the screen). See this StackOverflow question for other tail
alternatives.
The only problem is the temporary file may grow quite large. A possible workaround is to run a loop that only prints if the file has content and clear the file immediately afterwards, but that would cause a race condition.
Solution 2
I am surprised that this has't been answered correctly already. There is indeed a UNC path assigned to named pipes by the system, accessible on any machine in the network, which can be used like a normal file:
program.exe >\\.\pipe\StdOutPipe 2>\\.\pipe\StdErrPipe
Assuming pipes named "StdOutPipe" and "StdErrPipe" exist on this machine, this attempts to connect and write to them. The pipe
part is what specifies that you want a named pipe.
Solution 3
Not with the standard shell (CMD.EXE). For programmers, it's fairly easy. Just grab the two pipes of a process that you started.
n611x007
Updated on September 18, 2022Comments
-
n611x007 over 1 year
Is there a way to redirect the standard output of a process in Win32 console to a named pipe? Named pipes are built in to Windows and while they would be an useful concept, I've never seen them used from command line.
Ie. like
example.exe >\\.\mypipe
. (This syntax may not be correct but you get the point.) I would like to be able to redirect stdout and stderr to different pipes at the same time.I would like to avoid using physical files as a substitute, to escape dealing with IO slowness, IO buffers, file locks, access rights, available hard disk space, decision to overwrite, unmeant persistence, etc.
Another reason is because the traditional Windows set of tools are not designed around a (text) file based philosophy as much as in Unix. Also, named pipes couldn't easily be mounted in Windows, if at all.
Finally, there is the curiosity if a good concept could be put into good use.
-
ixe013 about 12 yearsYou mean like redirecting to a named pipe or a mailslot ? Do you have / are willing to write the receiving end ?
-
n611x007 over 11 yearsYes, like to a named pipe or mailslot. I don't yet have but willing to write the receiving end.
-
-
Fernando Gonzalez Sanchez over 9 yearsOnly prb is that the sample uses anonymous pipes, which dont support overlapped io (async) and thus are prone to deadlocks, or at least PeekNamedPipe must be used.
-
MSalters over 9 yearsBlocking waits are not deadlocks, and the fundamental problem (data consuming thread blocks producer thread from producing it) is not solved by overlapped I/O anyway.
-
Fernando Gonzalez Sanchez over 9 yearsI was meaning this: blogs.msdn.com/b/oldnewthing/archive/2011/07/07/10183884.aspx, a deadlock example.
-
MSalters over 9 years@FernandoGonzalezSanchez: Pretty much the same problem. Note that the recommended solution (extra thread) sidesteps any need for async I/O.
-
Fernando Gonzalez Sanchez over 9 yearsYeah, The prb in the msdn sample is that parent is stuck forever waiting, in function ReadFromPipe, line bSuccess = ReadFile(g_hChildStd_OUT_Rd, chBuf, BUFSIZE, &dwRead, NULL); will read 70 bytes 1st time, and 2nd time will stuck forever (PeekNamedPipe, which is missing, is non blocking).
-
arturn over 6 yearsI think this should be marked as the correct answer as Is just what is asking @n611x007 not external programs are required for doing this!
-
Erik Aronesty over 6 yearsSee below: you can use the UNC path assigned to a named pipe, and access it directly.
-
Erik Aronesty over 6 yearsthe problem is that you still need to launch a service of some kind that creates those pipes.... they do not exist independently of a program that created and are destroyed when the program goes away.
-
IS4 over 6 years@ErikAronesty I assumed these pipes already exist. Otherwise, there is no way to create them only with cmd.exe.
-
Erik Aronesty over 6 yearsYeah that's the cool thing about unix pipes, you can create pipes from the command line
-
alexchandel about 5 yearsThis answer is false. You can pipe to a named pipe from CMD.EXE (as documented above) via this syntax:
foo.exe > \\.\pipe\SomeFooPipe