C# - 배치 파일 실행하고 출력 결과를 얻는 방법
우선 배치 파일을 C#으로 실행하는 방법은 다음과 같이 간단합니다.
Process.Start("test.bat");
또는 ProcessStartInfo 타입을 이용해 복잡하게(?) 실행할 수 있습니다.
ProcessStartInfo psi = new ProcessStartInfo();
psi.FileName = "test.bat";
Process proc = Process.Start(psi);
더 복잡하게 실행하는 다음의 방법도 있습니다.
ProcessStartInfo psi = new ProcessStartInfo();
psi.FileName = "cmd.exe";
psi.Arguments = "/C test.bat";
Process.Start(psi);
위의 3가지 방법은 다른 듯 하지만, 실은 모두 똑같습니다. 결국 실행하면 마지막 방식으로 실행한 것처럼 cmd.exe로 "/C" 옵션을 경유해 배치 파일이 실행됩니다. 개인적으로는, 복잡하지만 제가 제어했다는 이유만으로 3번째 방법을 선호합니다.
그럼, 배치 파일을 실행한 이후 그 출력 결과를 가져오려면 어떻게 해야 할까요?
이를 위해 다음과 같이 Process.StandardOutput 속성을 이용해 ReadToEnd를 호출하면?
ProcessStartInfo psi = new ProcessStartInfo();
psi.FileName = "cmd.exe";
psi.Arguments = "/C test.bat";
Process proc = Process.Start(psi);
proc.WaitForExit();
string txt = proc.StandardOutput.ReadToEnd();
아쉽게도 이런 오류가 발생합니다.
System.InvalidOperationException was unhandled
_HResult=-2146233079
_message=StandardOut has not been redirected or the process hasn't started yet.
HResult=-2146233079
IsTransient=false
Message=StandardOut has not been redirected or the process hasn't started yet.
Source=System
StackTrace:
at System.Diagnostics.Process.get_StandardOutput()
at ConsoleApplication1.Program.CallType1() in e:\...\ConsoleApplication1\Program.cs:line 52
at ConsoleApplication1.Program.Main(String[] args) in e:\...\ConsoleApplication1\Program.cs:line 15
InnerException:
즉, StandardOutput 속성을 사용하려면 미리 ProcessStartInfo.RedirectStandardOutput 속성을 true로 명시해줘야 합니다.
ProcessStartInfo psi = new ProcessStartInfo();
psi.FileName = "cmd.exe";
psi.Arguments = "/C test.bat";
psi.RedirectStandardOutput = true;
Process proc = Process.Start(psi);
proc.WaitForExit();
string txt = proc.StandardOutput.ReadToEnd();
하지만, 이렇게 했어도 예외가 발생합니다.
System.InvalidOperationException was unhandled
_HResult=-2146233079
_message=The Process object must have the UseShellExecute property set to false in order to redirect IO streams.
HResult=-2146233079
IsTransient=false
Message=The Process object must have the UseShellExecute property set to false in order to redirect IO streams.
Source=System
StackTrace:
at System.Diagnostics.Process.StartWithShellExecuteEx(ProcessStartInfo startInfo)
at System.Diagnostics.Process.Start(ProcessStartInfo startInfo)
at ConsoleApplication1.Program.CallType1() in e:\...\ConsoleApplication1\Program.cs:line 49
at ConsoleApplication1.Program.Main(String[] args) in e:\...\ConsoleApplication1\Program.cs:line 15
InnerException:
친절하게도 이번엔 속성 이름까지 지정해주고 있습니다. 결국 다음과 같이 됩니다.
ProcessStartInfo psi = new ProcessStartInfo();
psi.FileName = "cmd.exe";
psi.Arguments = "/C test.bat";
psi.RedirectStandardOutput = true;
psi.UseShellExecute = false;
Process proc = Process.Start(psi);
proc.WaitForExit();
string txt = proc.StandardOutput.ReadToEnd();
위의 경우, ReadToEnd를 호출했기 때문에 Process.WaitForExit를 호출할 필요는 없습니다. 그래서 다음과 같이 작성해도 됩니다.
ProcessStartInfo psi = new ProcessStartInfo();
psi.FileName = "cmd.exe";
psi.Arguments = "/C test.bat";
psi.RedirectStandardOutput = true;
psi.UseShellExecute = false;
Process proc = Process.Start(psi);
string txt = proc.StandardOutput.ReadToEnd();
만약, 출력 결과를 라인 단위로 가져오고 싶다면 이렇게 작성할 수 있습니다.
ProcessStartInfo psi = new ProcessStartInfo();
psi.FileName = "cmd.exe";
psi.Arguments = "/C test.bat";
psi.RedirectStandardOutput = true;
psi.UseShellExecute = false;
Process proc = Process.Start(psi);
while (true)
{
string txt = proc.StandardOutput.ReadLine(); // blocking 함수
if (txt == null) // 프로세스가 종료한 경우 null 반환
{
break;
}
Console.WriteLine(txt);
}
[이 글에 대해서 여러분들과 의견을 공유하고 싶습니다. 틀리거나 미흡한 부분 또는 의문 사항이 있으시면 언제든 댓글 남겨주십시오.]