Windows como redirecionar o parâmetro do arquivo para stdout? (equivalente no Windows a `/dev/stdout`)

Windows como redirecionar o parâmetro do arquivo para stdout? (equivalente no Windows a `/dev/stdout`)

Consola do Windows:

  • A ferramenta A pode gravar dados binários em um arquivo, mas não tem opção para instruí-lo a usar stdout.
  • A ferramenta B pode ler dados binários do stdin e processar as informações nele contidas.

Como posso obter a saída de A canalizada através de B sem usar um arquivo intermediário?

Em outras palavras: qual é o equivalente do Windows /dev/stdout?

Responder1

O Windows possui um análogo para /dev/stdout, CON:

Imagino que ainda funcione, considerando o programa contínuo de “compatibilidade herdada” da Microsoft.

Ah.. encontrei. Suporte da Microsoftfornece uma lista de nomes reservados. Você não pode nomear um arquivo com esses nomes e eles têm significados especiais quando usados ​​como entradas ou saídas.

Você PODE usar CON como um dispositivo de saída para enviar para stdout.

A lista:

   Name    Function
   ----    --------
   CON     Keyboard and display
   PRN     System list device, usually a parallel port
   AUX     Auxiliary device, usually a serial port
   CLOCK$  System real-time clock
   NUL     Bit-bucket device
   A:-Z:   Drive letters
   COM1    First serial communications port
   LPT1    First parallel printer port
   LPT2    Second parallel printer port
   LPT3    Third parallel printer port
   COM2    Second serial communications port
   COM3    Third serial communications port
   COM4    Fourth serial communications port

Responder2

O Windows não tem equivalente direto ao /dev/stdout.


Aqui está minha tentativa de escrever um programa C# que cria umtubo nomeado, que pode ser fornecido ao programa A como nome de arquivo. Requer .NET v4.

(C# porque o compilador vem com tempo de execução .NET e qual computador não tem .NET atualmente?)

PipeServer.cs

using System;
using System.IO;
using System.IO.Pipes;

class PipeServer {
    static int Main(string[] args) {
        string usage = "Usage: PipeServer <name> <in | out>";
        if (args.Length != 2) {
            Console.WriteLine(usage);
            return 1;
        }
        
        string name = args[0];
        if (String.Compare(args[1], "in") == 0) {
            Pipe(name, PipeDirection.In);
        }
        else if (String.Compare(args[1], "out") == 0) {
            Pipe(name, PipeDirection.Out);
        }
        else {
            Console.WriteLine(usage);
            return 1;
        }
        return 0;
    }
    
    static void Pipe(string name, PipeDirection dir) {
        NamedPipeServerStream pipe = new NamedPipeServerStream(name, dir, 1);
        pipe.WaitForConnection();
        try {
            switch (dir) {
                case PipeDirection.In:
                    pipe.CopyTo(Console.OpenStandardOutput());
                    break;
                case PipeDirection.Out:
                    Console.OpenStandardInput().CopyTo(pipe);
                    break;
                default:
                    Console.WriteLine("unsupported direction {0}", dir);
                    return;
            }
        } catch (IOException e) {
            Console.WriteLine("error: {0}", e.Message);
        }
    }
}

Ajuntar com:

csc PipeServer.cs /r:System.Core.dll

cscpode ser encontrado em%SystemRoot%\Microsoft.NET\Framework64\<version>\csc.exe

Por exemplo, usando o .NET Client Profile v4.0.30319 em um Windows XP de 32 bits:

"C:\WINDOWS\Microsoft.NET\Framework\v4.0.30319\csc.exe" PipeServer.cs /r:System.Core.dll

Correr:

PipeServer foo in | programtwo

na janela um e:

programone \\.\pipe\foo

na janela dois.

Responder3

Baseado emgravidaderesposta de Eu criei uma versão estendida que permite que um processo seja iniciado diretamente sem a necessidade de usar várias janelas de terminal.

Uso geral:

PipeServer [in|out] [process name] [argument 1] [argument 2] [...]

A string "{pipe}" é então substituída pelo caminho de redirecionamento.

Exemplo do mundo real:

PipeServer.exe in "C:\Keil\UV4\Uv4.exe" -b "C:\Project\Project.uvproj" -j0 -o "{pipe}"

Esta linha de comandos pode ser inserida diretamente, por exemplo, no Eclipse para redirecionar o log de construção de um determinado construtor externo para StdOut.

Este é provavelmente o melhor que existe...

class PipeServer
{
    static
    int
    Main(string[] args)
    {
        if(args.Length < 2
        ||(System.String.Compare(args[0], "in")  != 0
        && System.String.Compare(args[0], "out") != 0)) {
            System.Console.WriteLine("Usage: PipeServer <in | out> <process> <args>");
            
            return 1;
        }
 
        ///////////////////////////////////
        // // // Process arguments // // //
        ///////////////////////////////////
        // Convert pipe direction
        System.IO.Pipes.PipeDirection pipe_dir = 0;
        if(System.String.Compare(args[0], "in") == 0) {
            pipe_dir = System.IO.Pipes.PipeDirection.In;
        }
        if(System.String.Compare(args[0], "out") == 0) {
            pipe_dir = System.IO.Pipes.PipeDirection.Out;
        }
        
        // Find process name to start
        string proc_name = args[1];
        
        // Build commandline argument string
        string proc_args = "";
        for(System.UInt16 i = 2; i < args.Length; i++) {
            if(args[i].IndexOf(" ") > -1) {
                proc_args += "\"" + args[i].Replace("\"", "\\\"") + "\" ";
            } else {
                proc_args += args[i] + " ";
            }
        }
        
        // Create server
        string                                pipe_name   = "";
        System.IO.Pipes.NamedPipeServerStream pipe_stream = null;
        for(System.UInt16 i = 1; i < 65535; i++) {
            // Generate new pipe name
            pipe_name = "pipeserver_" + System.Convert.ToString(i);
            
            try {
                // Start server
                pipe_stream = new System.IO.Pipes.NamedPipeServerStream(pipe_name, pipe_dir, 1);
                
                break;
            } catch(System.IO.IOException _) {
                continue;
            }
        }
        if(pipe_stream == null) {
            System.Console.WriteLine("Could not create pipe");
            
            return 1;
        }
        
        // Make sure the process knows about the pipe name
        proc_args = proc_args.Replace("{pipe}", "\\\\.\\pipe\\" + pipe_name);
        
        // Run process
        System.Diagnostics.Process proc = new System.Diagnostics.Process();
        proc.StartInfo.FileName  = proc_name;
        proc.StartInfo.Arguments = proc_args;
        proc.Start();
        
        // Connect pipes and wait until EOF
        pipe_stream.WaitForConnection();
        try {
            if(pipe_dir == System.IO.Pipes.PipeDirection.In) {
                pipe_stream.CopyTo(System.Console.OpenStandardOutput());
            }
            if(pipe_dir == System.IO.Pipes.PipeDirection.Out) {
                System.Console.OpenStandardInput().CopyTo(pipe_stream);
            }
        } catch (System.IO.IOException e) {
            System.Console.WriteLine("error: {0}", e.Message);
            
            return 1;
        }
        
        // Wait for process termination
        while(!proc.HasExited) {
            proc.WaitForExit();
        }
        
        // Return correct exit code
        return proc.ExitCode;
    }
}

informação relacionada