有没有办法重定向标准输出一个过程Win32 控制台到命名管道? 命名管道是 Windows 的内置功能,虽然它们是一个有用的概念,但我从未见过在命令行中使用它们。
即像example.exe >\\.\mypipe
. (这个语法可能不正确,但你明白我的意思。)我希望能够重定向标准输出和标准错误可同时传输至不同的管道。
我想避免使用物理文件作为替代品,以避免处理 IO 缓慢、IO 缓冲区、文件锁、访问权限、可用硬盘空间、覆盖决定、无意持久性等问题。
另一个原因是,传统的 Windows工具集并不是围绕基于(文本)文件的哲学进行设计的就像在 Unix 中一样. 此外,命名管道无法轻易地在 Windows 中安装,甚至根本无法安装。
最后,人们好奇一个好的概念是否能够得到很好的利用。
答案1
我不确定你为什么不想重定向到一个文件。我在这里提供两种方法。一种方法是重定向到一个文件并从中读取,另一种方法是一组程序。
命名管道
我所做的是为 .NET 4 编写两个程序。一个将输出发送到命名管道,另一个从该管道读取并显示到控制台。用法非常简单:
asdf.exe | NamedPipeServer.exe "APipeName"
在另一个控制台窗口中:
NamedPipeClient.exe "APipeName"
不幸的是,由于Windows 命令提示符中的管道运算符 ( ) 的限制,这只能重定向stdout
(或stdin
,或 组合),而不能单独重定向。如果您弄清楚如何通过该管道运算符发送,它应该可以工作。或者,可以修改服务器以启动您的程序并专门重定向。如果有必要,请在评论中告诉我(或自己动手);如果您有一些 C# 和 .NET“进程”库知识,这并不太难。stderr
|
stderr
stderr
如果在连接后关闭服务器,客户端也会立即关闭。如果在连接后关闭客户端,服务器会在您尝试通过它发送任何内容时立即关闭。无法重新连接破裂的管道,主要是因为我现在懒得做这么复杂的事情。它也仅限于每个服务器一个客户端。
源代码
这些是用 C# 编写的。解释起来没什么意义。它们使用 .NET命名管道服务器流和命名管道客户端流。
服务器:
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();
}
}
}
客户端:
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();
}
}
}
重定向到文件
type NUL>StdErr.temp
start powershell -c Get-Content StdErr.temp -Wait
MyExecutable.exe 2>StdErr.temp
- 创建一个空文件
- 启动一个监视文件的新控制台窗口
- 运行可执行文件并将
stderr
输出重定向到该文件
这提供了所需的效果,即一个控制台窗口用于观看stdout
(并提供stdin
),另一个用于观看stderr
。
任何模仿的方法tail
都可以。PowerShell 方法在 Windows 中原生运行,但可能有点慢(即写入文件和显示到屏幕之间存在一些延迟)。请参阅这个 StackOverflow 问题寻找其他tail
替代方案。
唯一的问题是临时文件可能会变得非常大。一个可能的解决方法是运行一个循环,仅在文件有内容时才打印,然后立即清除文件,但这会导致竞争条件。
答案2
我很惊讶这个问题还没有得到正确的回答。确实有一个UNC 路径由系统分配给命名管道,可在网络中的任何机器上访问,可以像普通文件一样使用:
program.exe >\\.\pipe\StdOutPipe 2>\\.\pipe\StdErrPipe
假设此机器上存在名为“StdOutPipe”和“StdErrPipe”的管道,这将尝试连接并写入它们。该pipe
部分指定您需要一个命名管道。
答案3
您希望 Windows 数据管道从服务器立即或稍后传输到客户端 DOS 窗口,而小型 RAM 驱动器可能会满足您的这一需求。相同的内存分配给数据,使用类似文件系统的名称进行写入/读取。客户端要么删除用完的文件并等待另一个文件,要么在计算机关闭时让它消失。