C#에서 어떤 외부 프로그램을 독립적으로 실행 시키고 그 결과를 받아야 하는 경우가 있다.
개인적인 경험으로는 C#에서 python으로 작성된 코드를 실행 시키고 그 결과를 받아오는 처리를 하는 경우가 몇 번 필요했었는데, 물론 C#에서 python은 연동하는 여러 방법들이 있지만, 그중 python을 마치 사용자가 콘솔에서 스크립트 실행 시키듯이 실행시키고 그 결과를 받아오는 것이 가장 깔금하다.
예컨대 아래와 같이 CMD에서 python을 실행시키는 것을 C#에서 Process를 이용해서 실행시키는 것이다.
C:\>python 'python 프로그램 이름'.py '프로그램에서 받는 파라미터 1' ...
PowerShell
복사
이것을 C#의 Process를 이용하면 C# 프로그램 상에서 동일한 결과를 얻을 수 있다. 코드는 아래와 같다.
public void StartProcess(IEnumerable<string> commands)
{
ProcessStartInfo psi = new ProcessStartInfo();
psi.FileName = "cmd.exe"; // cmd를 띄운다. powershell을 띄워도 무방. 아예 다른 프로그램의 path를 써도 된다.
psi.RedirectStandardInput = true; // input을 쓴다
psi.RedirectStandardOutput = true; // output을 쓴다
psi.RedirectStandardError = true; // pyton tqdm 메시지가 error에 찍힘
psi.UseShellExecute = false; // output을 true로 하려면 shell execute가 false여야 함
psi.CreateNoWindow = true; // 창을 새로 띄우지 않음
using (Process process = Process.Start(psi))
{
process.OutputDataReceived += OutputDataReceived; // output 이벤트 구독
process.ErrorDataReceived += ErrorDataReceived; // error 이벤트 구독
process.BeginOutputReadLine(); // output 시작
process.BeginErrorReadLine(); // error 시작
// cmd에 commad 입력을 위해 stream을 가져온다.
// StandardInput을 종료해야 EndOfStream을 처리할 수 있기 때문에 using으로 묶는다
using (StreamWriter sw = process.StandardInput)
{
if (sw.BaseStream.CanWrite)
{
foreach (string command in commands)
{
sw.WriteLine(command);
}
}
}
process.WaitForExit();
}
}
C#
복사
ProcessStartInfo에 들어가는 옵션에 대한 설명은 주석과 같고, 해당 ProcesStartInfo를 이용해서 Process를 시작하면 일단 CMD를 실행된다. —powershell을 설정했다면 powershell이 실행 된다.
CMD가 실행된 후에는 위에서 python 실행하는 예처럼 command를 입력해 주어야 하는데 그것은 process의 StandardInput의 StreamWriter를 가져와서 할 수 있다.
StreamWriter에 WriteLine에는 위에서 python을 실행하는 것을 줄 단위로 입력해 주면 된다. 만일 Anaconda 같은 것을 띄우고 python을 실행할 특정 경로로 이동하고 등의 일련의 과정이 있다면 아래 코드와 같이 여러 줄의 command를 넣으면 된다.
conda activate 'anaconda 이름' // anaconda 환경을 띄운다.
cd d:\dev\test // 실행할 python 코드가 있는 위치로 이동한다.
python 'python 프로그램 이름'.py param1 param2 ... // python을 실행하고 해당 python 코드에서 받는 파라미터를 넘겨준다.
PowerShell
복사
코드를 보면 알겠지만 이것은 CMD에서 python을 실행하는 것과 완전히 동일하다.
외부 프로그램을 실행시킨 후 해당 프로그램에서 출력하는 output을 받기 위해 OutputData와 ErrorData 이벤트를 구독하고 BeginOutputReadLine(), BeginErrorReadLine()을 실행한다. Error 는 마치 Exception이 발생한 것들에 대해서만 잡힐 것 같지만, 실제 프로그램의 Log 타입에 따라 Error로 출력되는 것들이 있으므로 Error만 나온다고 생각하면 안된다.
Output, Error 이벤트를 받는 메서드는 아래와 같이 구성하면 된다.
private void OutputDataReceived(object sender, DataReceivedEventArgs e)
{
if (!string.IsNullOrWhiteSpace(e.Data))
{
// log 출력 로직
if (Regex.IsMatch(e.Data, '찾을 pattern'))
{
// 처리 로직
}
}
}
private void ErrorDataReceived(object sender, DataReceivedEventArgs e)
{
if (!string.IsNullOrWhiteSpace(e.Data))
{
// log 출력 로직
if (Regex.IsMatch(e.Data, '찾을 pattern'))
{
// 처리 로직
}
}
}
C#
복사