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

25117
n611x007

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

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

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

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

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

14
Вы имеете в виду как перенаправление на именованный канал или почтовый ящик? Есть ли у вас / готовы написать получающий конец? ixe013 12 лет назад 1
Да, как для именованного канала или почтового ящика. У меня пока нет, но я хочу написать получающий конец. n611x007 12 лет назад 0

3 ответа на вопрос

9
IllidanS4

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

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

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

Я думаю, что это должно быть помечено как правильный ответ, поскольку это именно то, что спрашивает @ n611x007, для этого не требуются внешние программы! arturn 7 лет назад 0
проблема в том, что вам все еще нужно запустить какой-то сервис, который создает эти каналы .... они не существуют независимо от созданной программы и уничтожаются при ее выходе. Erik Aronesty 6 лет назад 0
@ErikAronesty Я предположил, что эти трубы уже существуют. В противном случае их невозможно создать только с помощью cmd.exe. IllidanS4 6 лет назад 0
Да, это крутая вещь о каналах Unix, вы можете создавать каналы из командной строки Erik Aronesty 6 лет назад 0
6
Bob

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


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

Я написал две программы для .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альтернатив.

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

Пользователи UNIX раздражают, потому что Windows снова не удается разумным образом реализовать 40-летнюю идею. Вам не нужно писать собственную программу каждый раз, когда вы хотите сделать что-то простое. * Facepalm * bambams 11 лет назад 2
Смотрите ниже: вы можете использовать UNC-путь, назначенный для именованного канала, и получить к нему прямой доступ. Erik Aronesty 6 лет назад 0
1
MSalters

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

Единственная причина в том, что в примере используются анонимные каналы, которые не поддерживают перекрывающийся io (асинхронный) и, следовательно, подвержены тупикам, или, по крайней мере, должен использоваться PeekNamedPipe. Fernando Gonzalez Sanchez 9 лет назад 1
Ожидания блокировки не являются взаимоблокировками, и фундаментальная проблема (поток данных блокирует поток производителя от его создания) в любом случае не решается с помощью перекрывающегося ввода-вывода. MSalters 9 лет назад 1
Я имел в виду это: http://blogs.msdn.com/b/oldnewthing/archive/2011/07/07/10183884.aspx, пример тупика. Fernando Gonzalez Sanchez 9 лет назад 0
@FernandoGonzalezSanchez: Почти та же проблема. Обратите внимание, что рекомендуемое решение (дополнительная нить) позволяет обойтись без асинхронного ввода-вывода. MSalters 9 лет назад 1
Да, в примере msdn указано, что родитель застрял навсегда в функции ReadFromPipe, строка bSuccess = ReadFile (g_hChildStd_OUT_Rd, chBuf, BUFSIZE и & dwRead, NULL); 1 раз прочитает 70 байт, а 2 раза застрянет навсегда (PeekNamedPipe, который отсутствует, не блокируется). Fernando Gonzalez Sanchez 9 лет назад 0