Есть ли способ перенаправитьстандартный выводпроцесса вконсоль 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
- Создать пустой файл
- Откройте новое консольное окно, которое будет следить за файлом.
- Запустить исполняемый файл и перенаправить
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-диском. Та же память выделяется для данных, записанных/прочитанных с именем, похожим на имя файловой системы. Клиент либо удаляет использованный файл и ждет другого, либо оставляет его исчезать при выключении компьютера.