Windows でファイル パラメータを stdout にリダイレクトする方法 (Windows の `/dev/stdout` に相当)

Windows でファイル パラメータを stdout にリダイレクトする方法 (Windows の `/dev/stdout` に相当)

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 が搭載されていないコンピューターなどあるでしょうか?)

パイプサーバー.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;
    }
}

関連情報