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