Windows에서 stdout을 명령 줄의 (이름이 지정된) 파이프로 리디렉션 할 수 있습니까?


17

리디렉션 할 수있는 방법이 표준 출력 에서 프로세스의 Win32 콘솔을 A와 명명 된 파이프는 ? 명명 된 파이프는 Windows에 내장되어 있으며 유용한 개념이지만 명령 줄에서 사용되는 것을 본 적이 없습니다.

즉. 처럼 example.exe >\\.\mypipe. (이 구문은 정확하지 않지만 요점을 알 수 있습니다.) stdoutstderr 을 동시에 다른 파이프 로 리디렉션 할 수 있기를 원합니다 .

IO 둔화, IO 버퍼, 파일 잠금, 액세스 권한, 사용 가능한 하드 디스크 공간, 덮어 쓰기 결정, 중요하지 않은 지속성 등을 처리하기 위해 실제 파일을 대체물로 사용하지 않으려 고합니다.

또 다른 이유는 전통적인 Windows 도구 세트가 Unix 에서처럼 (텍스트) 파일 기반 철학을 중심으로 설계되지 않았기 때문 입니다. 또한 명명 된 파이프는 Windows에서 쉽게 마운트 할 수 없었습니다.

마지막으로, 좋은 개념을 잘 활용하면 호기심이 생깁니다.


1
명명 된 파이프 나 메일 슬롯으로 리디렉션하는 것을 의미합니까? 당신은 수신 끝을 쓸 의향이 있습니까?
ixe013

예, 명명 된 파이프 나 메일 슬롯을 좋아합니다. 나는 아직 수신 끝을 쓸 의향이 없다.
n611x007

답변:


8

왜 파일로 리디렉션하고 싶지 않은지 잘 모르겠습니다. 여기서 제공 할 두 가지 방법이 있습니다. 한 가지 방법은 파일로 리디렉션하고 파일에서 읽는 방법이고 다른 방법은 프로그램 세트입니다.


명명 된 파이프

내가 한 것은 .NET 4 용으로 두 개의 프로그램을 작성하는 것이 었습니다. 하나는 명명 된 파이프로 출력을 보내고 다른 하나는이 파이프에서 읽은 다음 콘솔에 표시합니다. 사용법은 매우 간단합니다.

asdf.exe | NamedPipeServer.exe "APipeName"

다른 콘솔 창에서 :

NamedPipeClient.exe "APipeName"

불행히도, 이것은 Windows 명령 프롬프트에서 파이프 연산자 ( ) 의 제한으로 인해 자체적으로가 아니라 리디렉션 stdout(또는 stdin, 또는 결합) 만 할 수 있습니다 . 해당 파이프 연산자를 통해 보내는 방법을 알아 내면 제대로 작동합니다. 또는 프로그램을 시작하고 특히 리디렉션하도록 서버를 수정할 수 있습니다 . 그것이 필요한 경우, 의견으로 알려주십시오 (또는 직접 해보십시오). C # 및 .NET "프로세스"라이브러리 지식이 있으면 어렵지 않습니다.stderr|stderrstderr

서버클라이언트를 다운로드 할 수 있습니다 .

연결 후 서버를 닫으면 클라이언트가 즉시 닫힙니다. 연결 후 클라이언트를 닫으면 서버가 무언가를 보내려고하면 서버가 닫힙니다. 깨진 파이프를 다시 연결할 수는 없습니다. 주로 지금 너무 복잡한 일을 방해 할 수 없기 때문입니다. 또한 서버 당 하나의 클라이언트로 제한됩니다 .

소스 코드

이들은 C #으로 작성되었습니다. 그것을 설명하려는 것은별로 중요하지 않습니다. 그들은 .NET NamedPipeServerStreamNamedPipeClientStream을 사용합니다 .

서버:

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) 원하는 다른 효과를 제공합니다 stderr.

모방하는 모든 tail것이 작동합니다. PowerShell 방법은 Windows에서 기본적으로 작동하지만 약간 느릴 수 있습니다 (예 : 파일 쓰기와 화면 표시간에 약간의 대기 시간이 있음). 다른 대안 은 이 StackOverflow 질문 을 참조하십시오 tail.

유일한 문제는 임시 파일이 상당히 커질 수 있다는 것입니다. 가능한 해결 방법은 파일에 내용이있는 경우에만 인쇄하고 즉시 파일을 지우는 루프를 실행하지만 경쟁 조건을 야기 할 수 있습니다.


2
유닉스 사용자는 Windows가 40 년 된 아이디어를 현명한 방법으로 다시 구현하지 못했기 때문에 짜증이납니다. 기본 작업을 수행 할 때마다 사용자 정의 프로그램을 작성할 필요가 없습니다. facepalm
bambams

아래 참조 : 명명 된 파이프에 지정된 UNC 경로를 사용하여 직접 액세스 할 수 있습니다.
Erik Aronesty

15

이것이 올바르게 답변되지 않은 것에 놀랐습니다. 실제로 시스템에 의해 명명 된 파이프에 할당 된 UNC 경로 가 있으며 네트워크의 모든 시스템에서 액세스 할 수 있으며 일반 파일처럼 사용할 수 있습니다.

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

"StdOutPipe"및 "StdErrPipe"라는 파이프가이 시스템에 있다고 가정하면 연결 및 쓰기를 시도합니다. 이 pipe부분은 명명 된 파이프를 원한다는 것을 지정합니다.


나는 이것이 정답으로 표시되어야한다고 생각합니다. @ n611x007에게 묻는 것은 외부 프로그램이 필요하지 않습니다!
도착

문제는 여전히 파이프를 생성하는 일종의 서비스를 시작해야한다는 것입니다. ... 파이프는 프로그램이 사라지면 생성되고 파괴 된 프로그램과 독립적으로 존재하지 않습니다.
Erik Aronesty

@ErikAronesty이 파이프가 이미 존재한다고 가정했습니다. 그렇지 않으면 cmd.exe로만 만들 수있는 방법이 없습니다.
IllidanS4는 Monica를

네, 유닉스 파이프의 멋진 점입니다. 커맨드 라인에서 파이프를 만들 수 있습니다
Erik Aronesty

1

표준 셸 (CMD.EXE)에는 해당되지 않습니다. 프로그래머 에게는 매우 쉽습니다 . 시작한 프로세스의 두 파이프를 잡아라.


1
오직 prb만이 샘플이 익명의 파이프를 사용한다는 것인데,이 파이프는 중첩 된 io (비동기)를 지원하지 않으므로 교착 상태가 발생하기 쉬우거나 최소한 PeekNamedPipe를 사용해야합니다.
페르난도 곤잘레스 산체스

1
블로킹 대기는 교착 상태가 아니며 기본 문제 (데이터 소비 스레드가 생산자 스레드에서이를 생성하지 못하도록 차단)는 중첩 된 I / O로 해결되지 않습니다.
MSalters


1
@ FernandoGonzalezSanchez : 거의 같은 문제입니다. 권장 솔루션 (추가 스레드)은 비동기 I / O에 대한 모든 필요를 회피합니다.
MSalters

1
예, msdn 샘플의 prb는 부모가 영원히 대기하는 것입니다. ReadFromPipe 함수에서 line bSuccess = ReadFile (g_hChildStd_OUT_Rd, chBuf, BUFSIZE, & dwRead, NULL); 첫 번째 70 바이트를 읽고 두 번째 시간이 영구적으로 멈 춥니 다.
페르난도 곤잘레스 산체스

-1

서버에서 클라이언트 작업 창으로 즉시 또는 나중에 Windows 데이터 파이프에 대한 환경 설정은 작은 RAM 드라이브로 만족 될 수 있습니다. 파일 시스템과 같은 이름으로 쓰거나 읽은 동일한 메모리가 데이터에 할당됩니다. 클라이언트는 사용한 파일을 삭제하고 다른 파일을 기다리거나 컴퓨터가 종료 될 때 사라지도록 둡니다.

당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.