No Windows, posso redirecionar o stdout para um pipe (nomeado) na linha de comando?

No Windows, posso redirecionar o stdout para um pipe (nomeado) na linha de comando?

Existe uma maneira de redirecionar osaída padrãode um processo emConsola Win32para umtubo nomeado? Os pipes nomeados são integrados ao Windows e, embora sejam um conceito útil, nunca os vi usados ​​na linha de comando.

Ou seja. como example.exe >\\.\mypipe. (Essa sintaxe pode não estar correta, mas você entendeu.) Gostaria de poder redirecionarsaída padrãoestderrpara tubos diferentes ao mesmo tempo.

Eu gostaria de evitar o uso de arquivos físicos como substitutos, para evitar lidar com lentidão de E/S, buffers de E/S, bloqueios de arquivos, direitos de acesso, espaço disponível no disco rígido, decisão de sobrescrever, persistência indesejada, etc.

Outra razão é porque o Windows tradicionalkit de ferramentasnão são projetados em torno de uma filosofia baseada em arquivo (de texto) tantocomo no Unix. Além disso, pipes nomeados não poderiam ser facilmente montados no Windows, se é que poderiam ser montados.

Por fim, há a curiosidade de saber se um bom conceito pode ser bem aproveitado.

Responder1

Não sei por que você não deseja redirecionar para um arquivo. Existem dois métodos que fornecerei aqui. Um método é redirecionar e ler um arquivo, o outro é um conjunto de programas.


Pipes nomeados

O que fiz foi escrever dois programas para .NET 4. Um envia a saída para um canal nomeado, o outro lê esse canal e exibe no console. O uso é bastante simples:

asdf.exe | NamedPipeServer.exe "APipeName"

Em outra janela do console:

NamedPipeClient.exe "APipeName"

Infelizmente, isso só pode redirecionar stdout(ou stdin, ou combinado), não stderrpor si só, devido a limitações no operador pipe ( |) no prompt de comando do Windows. Se você descobrir como enviar stderrpor meio desse operador de pipe, isso deverá funcionar. Alternativamente, o servidor pode ser modificado para iniciar seu programa e redirecionar especificamente o arquivo stderr. Se for necessário, deixe um comentário (ou faça você mesmo); não é muito difícil se você tiver algum conhecimento de biblioteca de "processos" em C # e .NET.

Você pode baixar oservidore acliente.

Se você fechar o servidor após a conexão, o cliente será fechado imediatamente. Se você fechar o cliente após a conexão, o servidor será fechado assim que você tentar enviar algo por meio dele.Não é possível reconectar um cano quebrado, principalmente porque não posso me incomodar em fazer algo tão complicado agora. Também está limitado aum cliente por servidor.

Código fonte

Eles são escritos em C#. Não adianta muito tentar explicar. Eles usam o .NETNamedPipeServerStreameNamedPipeClientStream.

O servidor:

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();
        }
    }
}

O cliente:

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();
        }
    }
}

Redirecionando para um arquivo

type NUL>StdErr.temp
start powershell -c Get-Content StdErr.temp -Wait
MyExecutable.exe 2>StdErr.temp
  1. Crie um arquivo vazio
  2. Inicie uma nova janela do console que monitora o arquivo
  3. Execute o executável e redirecione stderra saída para esse arquivo

Isso fornece o efeito desejado de uma janela de console para assistir stdout(e fornecer stdin) e outra para assistir stderr.

Qualquer coisa que imite tailfuncionaria. O método PowerShell funciona nativamente no Windows, mas pode ser um pouco lento (ou seja, há alguma latência entre a escrita no arquivo e a exibição na tela). Veresta pergunta StackOverflowpara outras tailalternativas.

O único problema é que o arquivo temporário pode ficar muito grande. Uma solução possível é executar um loop que imprima apenas se o arquivo tiver conteúdo e limpar o arquivo imediatamente depois, mas isso causaria uma condição de corrida.

Responder2

Estou surpreso que isso ainda não tenha sido respondido corretamente. Existe de fato umCaminho UNCatribuído a pipes nomeados pelo sistema, acessível em qualquer máquina da rede, que pode ser usado como um arquivo normal:

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

Supondo que existam pipes chamados "StdOutPipe" e "StdErrPipe" nesta máquina, isso tenta conectar-se e gravar neles. A pipeparte é o que especifica que você deseja um canal nomeado.

Responder3

Suas preferências para um canal de dados do Windows de um servidor para uma janela do cliente, imediatamente ou mais tarde, podem ser satisfeitas com uma pequena unidade de RAM. A mesma memória é alocada para os dados, gravados/lidos com um nome semelhante ao do sistema de arquivos. O cliente exclui o arquivo usado e espera por outro, ou deixa-o desaparecer quando o computador é desligado.

informação relacionada