Windows, как перенаправить параметр файла в stdout? (эквивалент `/dev/stdout` в Windows)

Windows, как перенаправить параметр файла в stdout? (эквивалент `/dev/stdout` в Windows)

Консоль Windows:

  • Инструмент A может записывать двоичные данные в файл, но не имеет возможности указать ему использовать stdout.
  • Инструмент B может считывать двоичные данные из stdin и обрабатывать содержащуюся в них информацию.

Как можно передать вывод из A через B без использования промежуточного файла?

Другими словами: что является эквивалентом для Windows /dev/stdout?

решение1

В Windows есть аналог для /dev/stdout, CON:

Думаю, что это все еще работает, учитывая продолжающуюся программу Microsoft по «совместимости с устаревшими версиями».

Ага... нашел. Поддержка Майкрософтдает список зарезервированных имен. Вы не можете назвать файл этими именами, и они имеют особое значение при использовании в качестве входов или выходов.

ВОЗМОЖНО, вы сможете использовать CON в качестве устройства вывода для отправки в stdout.

Список:

   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

решение2

В Windows нет прямого эквивалента /dev/stdout.


Вот моя попытка написать программу на C#, которая создаетименованный канал, которое может быть дано программе A в качестве имени файла. Требуется .NET v4.

(C#, потому что компилятор поставляется со средой выполнения .NET, а на каком компьютере в наши дни нет .NET?)

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

Компилировать с помощью:

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

cscможно найти в%SystemRoot%\Microsoft.NET\Framework64\<version>\csc.exe

Например, при использовании .NET Client Profile v4.0.30319 в 32-разрядной версии Windows XP:

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

Бегать:

PipeServer foo in | programtwo

в окне один, и:

programone \\.\pipe\foo

в окне два.

решение3

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

Общее использование:

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

Затем строка "{pipe}" заменяется путем перенаправления.

Пример из реальной жизни:

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

Эту командную строку можно вставить непосредственно, например, в Eclipse, чтобы перенаправить журнал сборки определенного внешнего сборщика в StdOut.

Это, пожалуй, лучшее, что может быть...

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

Связанный контент