En Windows, ¿puedo redirigir la salida estándar a una tubería (con nombre) en la línea de comando?

En Windows, ¿puedo redirigir la salida estándar a una tubería (con nombre) en la línea de comando?

¿Hay alguna manera de redirigir elsalida estándarde un proceso enconsola win32a untubería con nombre? Las canalizaciones con nombre están integradas en Windows y, si bien serían un concepto útil, nunca las he visto utilizadas desde la línea de comandos.

Es decir. como example.exe >\\.\mypipe. (Es posible que esta sintaxis no sea correcta, pero entiendes el punto). Me gustaría poder redirigirsalida estándarystderra diferentes tuberías al mismo tiempo.

Me gustaría evitar el uso de archivos físicos como sustituto, para evitar tener que lidiar con la lentitud de IO, los buffers de IO, los bloqueos de archivos, los derechos de acceso, el espacio disponible en el disco duro, la decisión de sobrescribir, la persistencia no deseada, etc.

Otra razón es que el Windows tradicionalset de herramientasno están diseñados tanto en torno a una filosofía basada en archivos (de texto)como en Unix. Además, las canalizaciones con nombre no se podían montar fácilmente en Windows, en todo caso.

Por último, existe la curiosidad de saber si se podría poner en práctica un buen concepto.

Respuesta1

No estoy seguro de por qué no desea redirigir a un archivo. Hay dos métodos que proporcionaré aquí. Un método consiste en redirigir y leer desde un archivo, el otro es un conjunto de programas.


Tuberías con nombre

Lo que hice fue escribir dos programas para .NET 4. Uno envía la salida a una canalización con nombre, el otro lee desde esta canalización y la muestra en la consola. El uso es bastante simple:

asdf.exe | NamedPipeServer.exe "APipeName"

En otra ventana de la consola:

NamedPipeClient.exe "APipeName"

Desafortunadamente, esto solo puede redirigir stdout(o stdin, o combinado), no stderrpor sí solo, debido a limitaciones en el operador de canalización ( |) en el símbolo del sistema de Windows. Si descubres cómo enviar stderra través de ese operador de tubería, debería funcionar. Alternativamente, el servidor podría modificarse para iniciar su programa y redirigir específicamente stderr. Si es necesario, házmelo saber en un comentario (o hazlo tú mismo); no es demasiado difícil si tiene algunos conocimientos de la biblioteca de "Procesos" de C# y .NET.

Puedes descargar elservidory elcliente.

Si cierra el servidor después de la conexión, el cliente se cerrará inmediatamente. Si cierra el cliente después de la conexión, el servidor se cerrará tan pronto como intente enviar algo a través de él.No es posible volver a conectar una tubería rota, principalmente porque no puedo molestarme en hacer algo tan complicado en este momento. También está limitado aun cliente por servidor.

Código fuente

Estos están escritos en C#. No tiene mucho sentido intentar explicarlo. Usan el .NETNamedPipeServerStreamyNamedPipeClientStream.

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

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

Redirigir a un archivo

type NUL>StdErr.temp
start powershell -c Get-Content StdErr.temp -Wait
MyExecutable.exe 2>StdErr.temp
  1. Crear un archivo vacío
  2. Inicie una nueva ventana de consola que observe el archivo.
  3. Ejecute el ejecutable y redirija stderrla salida a ese archivo

Esto proporciona el efecto deseado de una ventana de consola para observar stdout(y proporcionar stdin) y otra para observar stderr.

Cualquier cosa que imite tailfuncionaría. El método PowerShell funciona de forma nativa en Windows, pero puede ser un poco lento (es decir, hay cierta latencia entre la escritura en el archivo y la visualización en la pantalla). Veresta pregunta de StackOverflowpara otras tailalternativas.

El único problema es que el archivo temporal puede crecer bastante. Una posible solución es ejecutar un bucle que solo imprima si el archivo tiene contenido y borrar el archivo inmediatamente después, pero eso causaría una condición de carrera.

Respuesta2

Me sorprende que esto aún no se haya respondido correctamente. De hecho hay unruta UNCasignado a canalizaciones con nombre por el sistema, accesible en cualquier máquina de la red, que se puede utilizar como un archivo normal:

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

Suponiendo que existan tuberías llamadas "StdOutPipe" y "StdErrPipe" en esta máquina, esto intenta conectarse y escribir en ellas. La pipeparte es lo que especifica que desea una canalización con nombre.

Respuesta3

Sus preferencias para una canalización de datos de Windows desde un servidor a una ventana de dos de cliente, ya sea inmediatamente o más tarde, podrían satisfacerse con una pequeña unidad RAM. Se asigna la misma memoria para los datos, escritos/leídos con un nombre similar al de un sistema de archivos. El cliente elimina el archivo usado y espera otro, o lo deja desaparecer cuando la computadora se apaga.

información relacionada