Kann ich unter Windows stdout auf eine (benannte) Pipe in der Befehlszeile umleiten?

Kann ich unter Windows stdout auf eine (benannte) Pipe in der Befehlszeile umleiten?

Gibt es eine Möglichkeit zur Umleitung derStandardausgabeeines Prozesses inWin32-Konsolezu einemBenannte Pipe? Named Pipes sind in Windows integriert und obwohl sie ein nützliches Konzept wären, habe ich noch nie gesehen, dass sie von der Befehlszeile aus verwendet werden.

D. h. wie example.exe >\\.\mypipe. (Diese Syntax ist möglicherweise nicht korrekt, aber Sie verstehen, was ich meine.) Ich möchte in der Lage sein, umzuleitenstdoutUndstderran verschiedene Rohre gleichzeitig.

Ich möchte die Verwendung physischer Dateien als Ersatz vermeiden, um mich nicht mit Problemen wie langsamer E/A-Verarbeitung, E/A-Puffern, Dateisperren, Zugriffsrechten, verfügbarem Festplattenspeicher, Entscheidungen zum Überschreiben, unbeabsichtigter Persistenz usw. herumschlagen zu müssen.

Ein weiterer Grund ist, dass die traditionellen WindowsWerkzeugsetsind nicht so sehr auf einer (text-)dateibasierten Philosophie aufgebautwie unter UnixAußerdem konnten Named Pipes in Windows nicht oder nur schwer gemountet werden.

Schließlich ist man neugierig, ob ein gutes Konzept auch sinnvoll umgesetzt werden kann.

Antwort1

Ich bin mir nicht sicher, warum Sie nicht zu einer Datei umleiten möchten. Ich werde hier zwei Methoden anbieten. Eine Methode besteht darin, zu einer Datei umzuleiten und aus dieser zu lesen, die andere ist eine Reihe von Programmen.


Benannte Pipes

Ich habe zwei Programme für .NET 4 geschrieben. Eines sendet die Ausgabe an eine benannte Pipe, das andere liest aus dieser Pipe und zeigt sie auf der Konsole an. Die Verwendung 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 umleiten stdout(oder stdinoder kombiniert), nicht allein. Wenn Sie herausfinden, wie Sie über diesen Pipe-Operator senden, sollte es funktionieren. Alternativ könnte der Server so geändert werden, dass er Ihr Programm startet und speziell umleitet . Wenn das notwendig ist, lassen Sie es mich in einem Kommentar wissen (oder machen Sie es selbst); es ist nicht allzu schwierig, wenn Sie über Kenntnisse der C#- und .NET-Bibliothek „Process“ verfügen.stderr|stderrstderr

Sie können dieServerund dasKlient.

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 darüber zu senden.Es ist nicht möglich, ein kaputtes Rohr wieder anzuschließen, vor allem, weil ich im Moment keine Lust habe, etwas so Kompliziertes zu tun. Es ist auch beschränkt aufein Client pro Server.

Quellcode

Diese sind in C# geschrieben. Es hat keinen Sinn, das zu erklären. Sie verwenden die .NETNamedPipeServerStreamUndNamedPipeClientStream.

Der Kellner:

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 zu einer 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. Ausführbare Datei ausführen und stderrAusgabe in diese Datei umleiten

Dadurch wird der gewünschte Effekt erzielt, indem ein Konsolenfenster beobachtet stdout(und bereitgestellt stdin) und ein anderes beobachtet wird stderr.

Alles, was nachgeahmt werden kann, tailwürde funktionieren. Die PowerShell-Methode funktioniert nativ in Windows, kann aber etwas langsam sein (d. h. es gibt eine gewisse Latenz zwischen dem Schreiben in die Datei und der Anzeige auf dem Bildschirm). Siehediese StackOverflow-Fragefür andere 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 druckt, wenn die Datei Inhalt hat, und die Datei unmittelbar danach zu löschen. Dies würde jedoch zu einem Race Condition führen.

Antwort2

Ich bin überrascht, dass dies nicht bereits richtig beantwortet wurde. Es gibt tatsächlich eineUNC-PfadVom System benannten Pipes zugewiesen, auf die von jedem Rechner im Netzwerk zugegriffen werden kann und die wie eine normale Datei verwendet werden können:

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

Vorausgesetzt, dass auf diesem Computer Pipes mit den Namen „StdOutPipe“ und „StdErrPipe“ vorhanden sind, wird versucht, eine Verbindung zu ihnen herzustellen und in sie zu schreiben. Dieser pipeTeil gibt an, dass Sie eine benannte Pipe wünschen.

Antwort3

Ihre Anforderungen an eine Windows-Datenpipeline von einem Server zu einem DOS-Fenster eines Clients entweder sofort oder später könnten mit einem kleinen RAM-Laufwerk erfüllt werden. Derselbe Speicher wird für die Daten reserviert und mit einem Dateisystem-ähnlichen Namen geschrieben/gelesen. Der Client löscht entweder die verbrauchte Datei und wartet auf eine neue oder lässt sie verschwinden, wenn der Computer herunterfährt.

verwandte Informationen