Windows에서 파일 매개변수를 stdout으로 리디렉션하는 방법은 무엇입니까? (Windows에서는 `/dev/stdout`에 해당)

Windows에서 파일 매개변수를 stdout으로 리디렉션하는 방법은 무엇입니까? (Windows에서는 `/dev/stdout`에 해당)

Windows 콘솔:

  • 도구 A는 바이너리 데이터를 파일에 쓸 수 있지만 stdout을 사용하도록 지시하는 옵션은 없습니다.
  • 도구 B는 stdin에서 바이너리 데이터를 읽고 그 안에 있는 정보를 처리할 수 있습니다.

중간 파일을 사용하지 않고 B를 통해 파이프된 A의 출력을 어떻게 얻을 수 있습니까?

즉, 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.


다음은명명된 파이프, 이는 프로그램 A에 파일 이름으로 제공될 수 있습니다. .NET v4가 필요합니다.

(C#은 컴파일러가 .NET 런타임과 함께 제공되기 때문에 요즘 어떤 컴퓨터에 .NET이 없나요?)

파이프서버.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

예를 들어 32비트 Windows XP에서 .NET Client Profile v4.0.30319를 사용하는 경우:

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

달리다:

PipeServer foo in | programtwo

창 1에서, 그리고:

programone \\.\pipe\foo

창 2에서.

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

관련 정보