在 Windows 中,我可以將 stdout 重新導向到命令列中的(命名)管道嗎?

在 Windows 中,我可以將 stdout 重新導向到命令列中的(命名)管道嗎?

有沒有辦法重定向標準輸出的一個過程在Win32 控制台到一個命名管道?命名管道內建於 Windows 中,雖然它們是一個有用的概念,但我從未見過它們在命令列中使用。

IE。喜歡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|stderrstderr

您可以下載伺服器客戶

如果連線後關閉伺服器,用戶端將立即關閉。如果您在連線後關閉客戶端,則當您嘗試透過伺服器傳送內容時,伺服器將立即關閉。重新連接破損的管道是不可能的,主要是因為我現在懶得做如此複雜的事情。也僅限於每台伺服器一個客戶端

原始碼

這些是用 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
  1. 建立一個空文件
  2. 啟動一個新的控制台視窗來監視文件
  3. 運行可執行檔並將stderr輸出重定向到該文件

這提供了一個控制台視窗觀看stdout(並提供stdin)和另一個控制台視窗觀看的所需效果stderr

任何模仿的東西tail都會起作用。 PowerShell 方法在 Windows 中本機工作,但可能有點慢(即寫入檔案和顯示到螢幕之間存在一些延遲)。看這個 StackOverflow 問題對於其他tail替代方案。

唯一的問題是臨時檔案可能會變得很大。一種可能的解決方法是運行一個循環,僅在文件有內容時才進行列印,然後立即清除該文件,但這會導致競爭條件。

答案2

我很驚訝這個問題還沒有得到正確的答案。確實有一個UNC 路徑由系統指派給命名管道,可以在網路中的任何電腦上訪問,可以像普通檔案一樣使用:

program.exe >\\.\pipe\StdOutPipe 2>\\.\pipe\StdErrPipe

假設本機上存在名為「StdOutPipe」和「StdErrPipe」的管道,這將嘗試連線並寫入它們。該pipe部分指定您需要命名管道。

答案3

您對立即或稍後從伺服器到客戶端 dos 視窗的 Windows 資料管道的偏好可能會透過小型 RAM 驅動器得到滿足。為資料分配相同的內存,並使用類似檔案系統的名稱進行寫入/讀取。客戶端要么刪除用完的文件並等待另一個文件,要么在電腦關閉時讓它消失。

相關內容