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


17

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

すなわち。のようなexample.exe >\\.\mypipe。(この構文は正しくないかもしれませんが、ポイントを得ることができます。)stdoutstderrを同時に異なるパイプにリダイレクトできるようにしたいと思います。

IOの遅さ、IOバッファー、ファイルロック、アクセス権、使用可能なハードディスク領域、上書きの決定、意味のない永続性などの処理を回避するために、物理ファイルを代わりに使用しないようにします。

もう1つの理由は、従来のWindows のツールセットは、Unixほど多くの(テキスト)ファイルベースの哲学に基づいて設計されていないためです。また、名前付きパイプは、Windowsに簡単にマウントできませんでした。

最後に、優れたコンセプトをうまく活用できれば好奇心があります。


1
名前付きパイプまたはメールスロットにリダイレクトするようなものですか?受信側に書き込みを行っていますか?
ixe013

はい、名前付きパイプまたはメールスロットのように。私はまだ受信側を作成していませんが、喜んで書き込みます。
n611x007

回答:


8

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


名前付きパイプ

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

asdf.exe | NamedPipeServer.exe "APipeName"

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

NamedPipeClient.exe "APipeName"

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

サーバークライアントをダウンロードできます

接続後にサーバーを閉じると、クライアントはすぐに閉じます。接続後にクライアントを閉じると、サーバーは何かを送信しようとするとすぐに閉じます。壊れたパイプを再接続することはできません。これは、ほとんどの場合、今はそれほど複雑なことをするのが面倒だからです。また、サーバーごと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そのファイルに出力をリダイレクトします

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

模倣tailするものはすべて動作します。PowerShellメソッドはWindowsでネイティブに機能しますが、少し遅い場合があります(つまり、ファイルへの書き込みから画面への表示までに多少の遅延があります)。他の選択肢については、このStackOverflowの質問をご覧くださいtail

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


2
UNIXユーザーは、Windowsが40年前のアイデアを賢明な方法で再び実装することに失敗したために悩まされています。基本的なことをするたびにカスタムプログラムを作成する必要はありません。手のひらを顔に当てる
bambams

以下を参照してください:名前付きパイプに割り当てられたUNCパスを使用して、直接アクセスできます。
エリックアロネスティ

15

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

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

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


@ n611x007にこれを行うために外部プログラムが必要ではないことを尋ねているだけですので、これは正しい答えとしてマークされるべきだと思います!
-arturn

問題は、それらのパイプを作成するサービスを起動する必要があることです。...作成されたプログラムとは独立して存在せず、プログラムが終了すると破棄されます。
エリックアロネスティ

@ErikAronestyこれらのパイプは既に存在すると仮定しました。それ以外の場合は、cmd.exeでのみ作成する方法はありません。
IllidanS4は、モニカを

ええ、それはUNIXパイプの
すごいところです。

1

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


1
prbのみが、サンプルが重複パイプ(非同期)をサポートしない匿名パイプを使用するため、デッドロックが発生しやすい、または少なくともPeekNamedPipeを使用する必要があります。
フェルナンドゴンザレスサンチェス

1
ブロッキング待機はデッドロックではなく、基本的な問題(データを消費するスレッドがプロデューサースレッドによるプロデュースをブロックする)は、いずれにしてもI / Oのオーバーラップによって解決されません。
–MSalters

私はこれを意味していました:blogs.msdn.com/b/oldnewthing/archive/2011/07/07/10183884.aspx、デッドロックの例。
フェルナンドゴンザレスサンチェス

1
@FernandoGonzalezSanchez:ほぼ同じ問題。推奨されるソリューション(余分なスレッド)は、非同期I / Oの必要性を回避することに注意してください。
–MSalters

1
ええ、msdnサンプルのprbは、関数ReadFromPipeの行bSuccess = ReadFile(g_hChildStd_OUT_Rd、chBuf、BUFSIZE、&dwRead、NULL)で、親が永遠に待機しているということです。1回目は70バイトを読み取り、2回目は永久にスタックします(欠落しているPeekNamedPipeはブロックされません)。
フェルナンドゴンザレスサンチェス

-1

サーバーからクライアントdosウィンドウへのデータのWindowsパイプの設定は、すぐにまたは後で、小さなRAMドライブで満たされる可能性があります。同じメモリがデータに割り当てられ、ファイルシステムのような名前で読み書きされます。クライアントは、使用済みのファイルを削除して別のファイルを待機するか、コンピューターがシャットダウンしたときにファイルが消えるようにします。

弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.