В Windows я могу перенаправить стандартный вывод в (именованный) канал в командной строке?

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

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

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

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

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

4 ответа

Решение

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


Именованные трубы

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

asdf.exe | NamedPipeServer.exe "APipeName"

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

NamedPipeClient.exe "APipeName"

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

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

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

Исходный код

Они написаны на C#. Нет особого смысла пытаться это объяснить. Они используют.NET NamedPipeServerStream и NamedPipeClientStream.

Сервер:

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 альтернативы.

Единственная проблема - временный файл может стать довольно большим. Возможный обходной путь - запустить цикл, который печатает только в том случае, если в файле есть содержимое, и сразу же очищать файл, но это может вызвать состояние гонки.

Я удивлен, что на этот вопрос уже не ответили правильно. В действительности существует UNC-путь, назначенный именованным каналам системой, доступный на любом компьютере в сети, который можно использовать как обычный файл:

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

Предполагая, что каналы с именами "StdOutPipe" и "StdErrPipe" существуют на этом компьютере, это попытается соединиться и записать их. pipe Часть это то, что указывает, что вы хотите именованный канал.

Не со стандартной оболочкой (CMD.EXE). Для программистов это довольно просто. Просто возьмите две трубы процесса, который вы начали.

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

Другие вопросы по тегам