Windows 콘솔:
- 도구 A는 바이너리 데이터를 파일에 쓸 수 있지만 stdout을 사용하도록 지시하는 옵션은 없습니다.
- 도구 B는 stdin에서 바이너리 데이터를 읽고 그 안에 있는 정보를 처리할 수 있습니다.
중간 파일을 사용하지 않고 B를 통해 파이프된 A의 출력을 어떻게 얻을 수 있습니까?
즉, 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
.
다음은명명된 파이프, 이는 프로그램 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;
}
}