web-dev-qa-db-ja.com

Windowsでは、コマンドラインでstdoutを(名前付き)パイプにリダイレクトできますか?

Win32コンソール のプロセスの 標準出力名前付きパイプ にリダイレクトする方法はありますか?名前付きパイプはWindowsに組み込まれており、便利なコンセプトですが、コマンドラインから使用されることはありません。

つまり。お気に入り example.exe >\\.\mypipe。 (この構文は正しくないかもしれませんが、要点はわかります。)stdoutおよびstderrを同時に別のパイプにリダイレクトできるようにしたいと思います。

IO slowness、IO buffers、file locks、access rights、available hard disk space)を回避するために、物理ファイルを代替として使用しない、上書きする決定、意味のない永続性など。

もう1つの理由は、従来のWindows ツールのセット が(テキスト)ファイルベースの哲学に基づいて設計されていないためです nixの場合と同様 。また、名前付きパイプをWindowsにマウントすることはできません。

最後に、優れたコンセプトをうまく活用できるかどうかは好奇心です。

19
n611x007

ファイルにリダイレクトしたくない理由がわかりません。ここで提供する方法は2つあります。 1つはファイルへのリダイレクトとファイルからの読み取り、もう1つは一連のプログラムです。


名前付きパイプ

私がしたことは、.NET 4用の2つのプログラムを作成することでした。1つは出力を名前付きパイプに送信し、もう1つはこのパイプから読み取り、コンソールに表示します。使い方は非常に簡単です:

asdf.exe | NamedPipeServer.exe "APipeName"

別のコンソールウィンドウで:

NamedPipeClient.exe "APipeName"

残念ながら、これはstdout(またはstdinまたはそれらの組み合わせ)のみをリダイレクトでき、stderr自体はリダイレクトできません。これは、パイプ演算子(|)(Windowsコマンドプロンプト)。そのパイプ演算子を介してstderrを送信する方法を理解した場合、それは機能するはずです。または、サーバーを変更してプログラムを起動し、stderrをリダイレクトすることもできます。それが必要な場合は、コメントで知らせてください(または自分で行ってください)。 C#と.NETの「プロセス」ライブラリに関する知識があれば、それほど難しくありません。

server および client をダウンロードできます。

接続後にサーバーを閉じると、クライアントはすぐに閉じます。接続後にクライアントを閉じると、それを介して何かを送信しようとするとすぐにサーバーが閉じます。壊れたパイプを再接続することはできません。今はとても複雑なもの。また、サーバーごとに1つのクライアントに制限されます。

ソースコード

これらはC#で記述されています。それを説明しようとしてもあまり意味がありません。 .NET NamedPipeServerStream および NamedPipeClientStream を使用します。

サーバー:

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.IO.Pipes;
using System.IO;

namespace NamedPipeServer
{
    class Program
    {
        static void Main(string[] args)
        {
            if (args == null || args.Length == 0)
            {
                Console.Error.WriteLine("[NamedPipeServer]: Need pipe name.");
                return;
            }

            NamedPipeServerStream PipeServer = new NamedPipeServerStream(args[0], System.IO.Pipes.PipeDirection.Out);
            PipeServer.WaitForConnection();
            StreamWriter PipeWriter = new StreamWriter(PipeServer);
            PipeWriter.AutoFlush = true;

            string tempWrite;

            while ((tempWrite = Console.ReadLine()) != null)
            {
                try
                {
                    PipeWriter.WriteLine(tempWrite);
                }
                catch (IOException ex)
                {
                    if (ex.Message == "Pipe is broken.")
                    {
                        Console.Error.WriteLine("[NamedPipeServer]: NamedPipeClient was closed, exiting");
                        return;
                    }
                }
            }

            PipeWriter.Close();
            PipeServer.Close();
        }
    }
}

クライアント:

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.IO.Pipes;
using System.IO;

namespace NamedPipeClient
{
    class Program
    {
        static void Main(string[] args)
        {
            if (args == null || args.Length == 0)
            {
                Console.Error.WriteLine("[NamedPipeClient]: Need pipe name.");
                return;
            }

            NamedPipeClientStream PipeClient = new NamedPipeClientStream(".", args[0], System.IO.Pipes.PipeDirection.In);
            PipeClient.Connect();
            StreamReader PipeReader = new StreamReader(PipeClient);

            string tempRead;

            while ((tempRead = PipeReader.ReadLine()) != null)
            {
                Console.WriteLine(tempRead);
            }

            PipeReader.Close();
            PipeClient.Close();
        }
    }
}

ファイルにリダイレクトする

type NUL>StdErr.temp
start powershell -c Get-Content StdErr.temp -Wait
MyExecutable.exe 2>StdErr.temp
  1. 空のファイルを作成する
  2. ファイルを監視する新しいコンソールウィンドウを開始する
  3. 実行可能ファイルを実行し、stderr出力をそのファイルにリダイレクトします

これにより、stdoutを監視する(およびstdinを提供する)1つのコンソールウィンドウと、stderrを監視する別のコンソールウィンドウの望ましい効果が得られます。

tailを模倣したものであれば何でも機能します。 PowerShellメソッドはWindowsでネイティブに機能しますが、少し遅い場合があります(つまり、ファイルへの書き込みと画面への表示の間に待ち時間が発生します)。他のtail代替案については、 このStackOverflowの質問 を参照してください。

唯一の問題は、一時ファイルが非常に大きくなる可能性があることです。考えられる回避策は、ファイルにコンテンツがある場合にのみ印刷するループを実行し、直後にファイルをクリアすることですが、これにより競合状態が発生します。

8
Bob

これがまだ正しく答えられていないことに驚いています。実際、システムによって名前付きパイプに割り当てられた NCパス があり、ネットワーク内の任意のマシンからアクセス可能であり、通常のファイルのように使用できます。

program.exe >\\.\pipe\StdOutPipe 2>\\.\pipe\StdErrPipe

「StdOutPipe」および「StdErrPipe」という名前のパイプがこのマシンに存在すると想定すると、これはそれらに接続して書き込みを試みます。 pipeの部分は、名前付きパイプが必要であることを指定するものです。

標準のシェル(CMD.EXE)では使用できません。プログラマにとっては かなり簡単 です。開始したプロセスの2つのパイプを取得するだけです。

1
MSalters