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:

考慮到微軟正在進行的「舊版相容性」計劃,我想它仍然有效。

啊..找到了。 微軟支援給出保留名稱的列表.您不能用這些名稱來命名文件,並且它們在用作輸入或輸出時具有特殊含義。

您也許可以使用 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

例如,在 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

在第一個視窗中,並且:

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

相關內容