Можно ли в Windows перенаправить stdout в (именованный) канал в командной строке?

Можно ли в Windows перенаправить stdout в (именованный) канал в командной строке?

Есть ли способ перенаправитьстандартный выводпроцесса вконсоль Win32кименованный канал? Именованные каналы встроены в Windows, и хотя они были бы полезной концепцией, я никогда не видел, чтобы они использовались из командной строки.

То есть, как example.exe >\\.\mypipe. (Этот синтаксис может быть неверным, но вы поняли суть.) Я хотел бы иметь возможность перенаправлятьстандартный выводиstderrк разным трубам одновременно.

Я бы хотел избежать использования физических файлов в качестве замены, чтобы не иметь дела с медленностью ввода-вывода, буферами ввода-вывода, блокировками файлов, правами доступа, доступным местом на жестком диске, решениями о перезаписи, непреднамеренным сохранением и т. д.

Другая причина в том, что традиционная Windowsнабор инструментовне разработаны на основе философии (текстовых) файловкак в Unix. Кроме того, именованные каналы нелегко монтировать в Windows, если это вообще возможно.

Наконец, возникает любопытство: можно ли воплотить хорошую концепцию в жизнь?

решение1

Я не уверен, почему вы не хотите перенаправить в файл. Есть два метода, которые я здесь предоставлю. Один метод — перенаправить в файл и прочитать из него, другой — набор программ.


Именованные каналы

Я написал две программы для .NET 4. Одна отправляет вывод в именованный канал, другая читает из этого канала и выводит на консоль. Использование довольно простое:

asdf.exe | NamedPipeServer.exe "APipeName"

В другом окне консоли:

NamedPipeClient.exe "APipeName"

К сожалению, это может только перенаправить stdout(или stdin, или комбинированно), а не stderrсамо по себе, из-за ограничений оператора конвейера ( |) в командной строке Windows. Если вы разберетесь, как отправить stderrчерез этот оператор конвейера, это должно сработать. В качестве альтернативы сервер можно изменить для запуска вашей программы и специально перенаправить stderr. Если это необходимо, дайте мне знать в комментарии (или сделайте это сами); это не так уж сложно, если у вас есть некоторые знания библиотеки C# и .NET "Process".

Вы можете скачатьсервериклиент.

Если закрыть сервер после подключения, клиент закроется немедленно. Если закрыть клиент после подключения, сервер закроется сразу, как только вы попытаетесь что-то через него отправить.Невозможно переподключить сломанную трубу, в основном потому, что я не могу сейчас заниматься чем-то таким сложным. Это также ограниченоодин клиент на сервер.

Исходный код

Они написаны на 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

Ваши предпочтения по каналу данных Windows от сервера к клиентскому окну dos немедленно или позже могут быть удовлетворены небольшим RAM-диском. Та же память выделяется для данных, записанных/прочитанных с именем, похожим на имя файловой системы. Клиент либо удаляет использованный файл и ждет другого, либо оставляет его исчезать при выключении компьютера.

Связанный контент