在 Windows 中,我可以将标准输出重定向到命令行中的(命名)管道吗?

n61*_*007 23 windows redirection command-line pipe named-pipe

有没有办法将Win32 控制台中进程的标准输出重定向到命名管道?命名管道内置于 Windows 中,虽然它们是一个有用的概念,但我从未见过它们从命令行使用。

IE。喜欢example.exe >\\.\mypipe。(此语法可能不正确,但您明白了。)我希望能够同时将stdoutstderr重定向到不同的管道。

我想避免使用物理文件作为替代,以避免处理 IO 缓慢、IO 缓冲区、文件锁、访问权限、可用硬盘空间、决定覆盖、无意义的持久性等。

另一个原因是因为传统的 Windows工具集不像在 Unix 中那样围绕基于(文本)文件的哲学设计。此外,命名管道不能轻易安装在 Windows 中,如果有的话。

最后,好奇一个好的概念是否可以得到很好的使用。

IS4*_*IS4 27

我很惊讶这还没有得到正确回答。确实有一个由系统分配给命名管道的UNC 路径,可以在网络中的任何机器上访问,可以像普通文件一样使用:

program.exe >\\.\pipe\StdOutPipe 2>\\.\pipe\StdErrPipe
Run Code Online (Sandbox Code Playgroud)

假设这台机器上存在名为“StdOutPipe”和“StdErrPipe”的管道,这将尝试连接并写入它们。该pipe部分是指定您需要命名管道的部分。

  • @ErikAronesty 我认为这些管道已经存在。否则,无法仅使用 cmd.exe 创建它们。 (3认同)

Bob*_*Bob 10

我不确定您为什么不想重定向到文件。我将在这里提供两种方法。一种方法是重定向到文件并从中读取,另一种方法是一组程序。


命名管道

我所做的是为 .NET 4 编写两个程序。一个将输出发送到命名管道,另一个从该管道读取并显示到控制台。用法很简单:

asdf.exe | NamedPipeServer.exe "APipeName"
Run Code Online (Sandbox Code Playgroud)

在另一个控制台窗口中:

NamedPipeClient.exe "APipeName"
Run Code Online (Sandbox Code Playgroud)

不幸的是,由于Windows 命令提示符中管道运算符 ( ) 的限制,这只能重定向stdout(或stdin,或组合),而不能单独重定向。如果您弄清楚如何通过该管道操作员发送,它应该可以工作。或者,可以修改服务器以启动您的程序并专门重定向. 如果有必要,请在评论中告诉我(或自己做);如果您有一些 C# 和 .NET“进程”库知识,这并不太难。stderr|stderrstderr

您可以下载服务器客户端

如果在连接后关闭服务器,客户端将立即关闭。如果您在连接后关闭客户端,服务器将在您尝试通过它发送内容时立即关闭。重新连接损坏的管道是不可能的,主要是因为我现在懒得做这么复杂的事情。它也仅限于每个服务器一个客户端

源代码

这些是用 C# 编写的。试图解释它没有多大意义。他们使用 .NET NamedPipeServerStreamNamedPipeClientStream

服务器:

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();
        }
    }
}
Run Code Online (Sandbox Code Playgroud)

客户端:

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();
        }
    }
}
Run Code Online (Sandbox Code Playgroud)

重定向到文件

type NUL>StdErr.temp
start powershell -c Get-Content StdErr.temp -Wait
MyExecutable.exe 2>StdErr.temp
Run Code Online (Sandbox Code Playgroud)
  1. 创建一个空文件
  2. 启动一个新的控制台窗口来监视文件
  3. 运行可执行文件并将stderr输出重定向到该文件

这提供了一个控制台窗口观看stdout(并提供stdin)和另一个观看的预期效果stderr

任何模仿的东西tail都会起作用。PowerShell 方法本机在 Windows 中工作,但可能有点慢(即在写入文件和显示到屏幕之间存在一些延迟)。有关其他替代方案,请参阅此 StackOverflow 问题tail

唯一的问题是临时文件可能会变得非常大。一种可能的解决方法是运行一个循环,仅在文件有内容时才打印并在之后立即清除文件,但这会导致竞争条件。

  • UNIX 用户很恼火,因为 Windows 再次未能以明智的方式实现 40 年前的想法。您不需要每次想要做基本的事情时都编写自定义程序。*面掌* (3认同)