Kann ich stdout in Windows zu einer (benannten) Pipe in der Befehlszeile umleiten?

25238
n611x007

Gibt es eine Möglichkeit, die Standardausgabe eines Prozesses in der Win32-Konsole an eine Named Pipe umzuleiten ? Named Pipes sind in Windows integriert, und obwohl sie ein nützliches Konzept wären, habe ich sie noch nie von der Kommandozeile aus gesehen.

Ie. wie example.exe >\\.\mypipe. (Diese Syntax ist möglicherweise nicht korrekt, aber Sie verstehen den Punkt.) Ich möchte stdout und stderr gleichzeitig auf verschiedene Pipes umleiten können.

Ich möchte vermeiden, physische Dateien als Ersatz zu verwenden, um den Umgang mit E / A-Langsamkeit, E / A-Puffern, Dateisperren, Zugriffsrechten, verfügbarem Festplattenspeicher, Überschreibungsentscheidung, ungewollter Persistenz usw. zu vermeiden.

Ein weiterer Grund ist, dass die traditionellen Windows- Tools nicht so sehr auf einer (text-) dateibasierten Philosophie basieren wie in Unix . Wenn überhaupt, können Named Pipes nicht einfach in Windows eingebunden werden.

Schließlich besteht die Neugier, ob ein gutes Konzept sinnvoll eingesetzt werden kann.

14
Sie meinen, Sie möchten zu einer Named Pipe oder einem Mail-Slot umleiten? Haben Sie / sind Sie bereit, das empfangende Ende zu schreiben? ixe013 vor 11 Jahren 1
Ja, wie eine Named Pipe oder ein Mailslot. Ich habe noch nicht, aber ich bin bereit, das empfangende Ende zu schreiben. n611x007 vor 11 Jahren 0

3 Antworten auf die Frage

9
IllidanS4

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.

Ich denke, das sollte als die richtige Antwort markiert werden, da gerade was @ n611x007 fragt, für das sind keine externen Programme erforderlich! arturn vor 6 Jahren 0
Das Problem ist, dass Sie immer noch einen Dienst starten müssen, der diese Pipes erstellt. Sie existieren nicht unabhängig von einem Programm, das erstellt wurde, und werden zerstört, wenn das Programm wegfällt. Erik Aronesty vor 6 Jahren 0
@ErikAronesty Ich nahm an, dass diese Pfeifen bereits existieren. Ansonsten gibt es keine Möglichkeit, sie nur mit cmd.exe zu erstellen. IllidanS4 vor 6 Jahren 0
Ja, das ist das Coole an Unix-Pipes. Sie können Pipes von der Kommandozeile aus erstellen Erik Aronesty vor 6 Jahren 0
6
Bob

Ich bin nicht sicher, warum Sie nicht in eine Datei umleiten möchten. Ich werde hier zwei Methoden zur Verfügung stellen. Eine Methode besteht darin, eine Datei umzuleiten und aus einer Datei zu lesen, die andere besteht aus einer Reihe von Programmen.


Named Pipes

Was ich getan habe, war das Schreiben von zwei Programmen für .NET 4. Eines sendet eine Ausgabe an eine Named Pipe, das andere liest aus dieser Pipe und zeigt sie an der Konsole an. Die Nutzung ist ganz einfach:

asdf.exe | NamedPipeServer.exe "APipeName" 

In einem anderen Konsolenfenster:

NamedPipeClient.exe "APipeName" 

Leider kann dies aufgrund von Einschränkungen des Pipe-Operators ( ) in der Windows-Eingabeaufforderung nur von alleine stdout(oder stdinkombiniert) umgeleitet werden . Wenn Sie herausfinden, wie Sie diesen Pipe-Operator senden, sollte dies funktionieren. Alternativ kann der Server geändert werden, um Ihr Programm zu starten und gezielt umzuleiten . Wenn das notwendig ist, lassen Sie es mich in einem Kommentar wissen (oder machen Sie es selbst). Es ist nicht zu schwierig, wenn Sie über Kenntnisse in der C # - und .NET-Bibliothek "Process" verfügen.stderr|stderrstderr

Sie können den Server und den Client herunterladen .

Wenn Sie den Server nach der Verbindung schließen, wird der Client sofort geschlossen. Wenn Sie den Client nach der Verbindung schließen, wird der Server geschlossen, sobald Sie versuchen, etwas über ihn zu senden. Es ist nicht möglich, eine kaputte Pipe wieder anzuschließen, vor allem, weil ich mich nicht darum kümmere, etwas so kompliziertes zu machen. Es ist auch auf einen Client pro Server beschränkt .

Quellcode

Diese sind in C # geschrieben. Es gibt keinen Grund, es zu erklären. Sie verwenden .NET NamedPipeServerStream und NamedPipeClientStream .

Der 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(); } } } 

Der Kunde:

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(); } } } 

Umleitung in eine Datei

type NUL>StdErr.temp start powershell -c Get-Content StdErr.temp -Wait MyExecutable.exe 2>StdErr.temp 
  1. Erstellen Sie eine leere Datei
  2. Starten Sie ein neues Konsolenfenster, das die Datei überwacht
  3. Führen Sie die ausführbare Datei aus und leiten Sie die stderrAusgabe in diese Datei um

Dies bietet den gewünschten Effekt eines Konsolenfensters zum Ansehen stdout(und Bereitstellen stdin) und eines weiteren zum Beobachten stderr.

Alles, was imitiert, tailwürde funktionieren. Die PowerShell-Methode funktioniert nativ unter Windows, kann jedoch etwas langsam sein (dh zwischen dem Schreiben der Datei und dem Anzeigen auf dem Bildschirm gibt es eine gewisse Latenz). In dieser StackOverflow-Frage finden Sie weitere tailAlternativen.

Das einzige Problem ist, dass die temporäre Datei ziemlich groß werden kann. Eine mögliche Problemumgehung besteht darin, eine Schleife auszuführen, die nur dann druckt, wenn die Datei Inhalt enthält, und die Datei unmittelbar danach zu löschen. Dies würde jedoch eine Racebedingung verursachen.

Unix-Benutzer sind ärgerlich, weil es Windows erneut nicht gelingt, eine 40 Jahre alte Idee sinnvoll umzusetzen. Sie sollten nicht jedes Mal ein benutzerdefiniertes Programm schreiben müssen, wenn Sie eine grundlegende Sache ausführen möchten. * facepalm * bambams vor 10 Jahren 2
Siehe unten: Sie können den UNC-Pfad verwenden, der einer Named Pipe zugewiesen ist, und direkt darauf zugreifen. Erik Aronesty vor 6 Jahren 0
1
MSalters

Not with the standard shell (CMD.EXE). For programmers, it's fairly easy. Just grab the two pipes of a process that you started.

Prb ist nur, dass das Beispiel anonyme Pipes verwendet, die kein überlapptes io (async) unterstützen und daher anfällig für Deadlocks sind, oder mindestens PeekNamedPipe verwendet werden muss. Fernando Gonzalez Sanchez vor 9 Jahren 1
Das Blockieren von Wartezeiten ist kein Deadlocks, und das grundlegende Problem (der verbrauchende Thread blockiert den produzierenden Thread von Producer) wird durch ohnehin überlappende E / A nicht gelöst. MSalters vor 9 Jahren 1
Ich meinte folgendes: http://blogs.msdn.com/b/oldnewthing/archive/2011/07/07/10183884.aspx, ein Deadlock-Beispiel. Fernando Gonzalez Sanchez vor 9 Jahren 0
@FernandoGonzalezSanchez: Ziemlich dasselbe Problem. Beachten Sie, dass die empfohlene Lösung (zusätzlicher Thread) keine asynchrone E / A benötigt. MSalters vor 9 Jahren 1
Ja, das Prb im msdn-Beispiel ist, dass das übergeordnete Element immer in der Funktion ReadFromPipe in der Zeile bSuccess = ReadFile (g_hChildStd_OUT_Rd, chBuf, BUFSIZE, & dwRead, NULL) steht. liest 70 Bytes beim ersten Mal, und das zweite Mal bleibt für immer hängen (PeekNamedPipe, das fehlt, blockiert nicht). Fernando Gonzalez Sanchez vor 9 Jahren 0