2010-06-16 4 views
1

쉘 리디렉션이 System.Diagnostics.Process 클래스에서 작동하지 않는 이유를 설명해 주시겠습니까? 다음 스 니펫을 사용하여 출력 스트림을 파일로 리디렉션하려고합니다.C에서 stdout을 리디렉션 할 때의 문제 #

Process p = new Process(); 
p.StartInfo = new ProcessStartInfo(); 
p.StartInfo.FileName = "java.exe"; 
p.StartInfo.Arguments = @"> c:\Temp\test.log 2>&1"; 
p.StartInfo.UseShellExecute = true; 
p.Start(); 

비슷한 코드가 파이썬에서 문제없이 작동합니다. 출력 스트림을 프로그래밍 방식으로 읽는 것이 내 응용 프로그램에서 시작된 프로세스가 많기 때문에 바람직한 해결책으로 보이지 않습니다.

답변

2

직접 연결된 셸이 없기 때문에 리디렉션을 수행 할 수 없습니다. cmd.exe 세션을 실행할 수 있지만 적절한 방법은 RedirectStandardOutput/Error 속성을 사용하는 것입니다. 많은 프로세스가있을 때 문제가 없습니다. 이것은 이것을 위해 사용하는 클래스입니다.

class HandleExecutable { 
     private DataReceivedEventHandler outputHandler; 

     public DataReceivedEventHandler OutputHandler 
     { 
      set { outputHandler = value; } 
     } 
     private DataReceivedEventHandler errorHandler; 

     public DataReceivedEventHandler ErrorHandler 
     { 
      set { errorHandler = value; } 
     } 

     public void callExecutable(string executable, string args) 
     { 
      string commandLine = executable; 
      string args = args; 
      ProcessStartInfo psi = new ProcessStartInfo(commandLine); 
      psi.UseShellExecute = false; 
      psi.LoadUserProfile = false; 
      psi.RedirectStandardOutput = true; 
      psi.RedirectStandardError = true; 
      psi.WindowStyle = ProcessWindowStyle.Minimized; 
      psi.CreateNoWindow = true; 
      psi.Arguments = args; 
      p = new Process(); 
      p.StartInfo = psi; 
      try 
      { 
       p.Start(); 
       p.BeginOutputReadLine(); 
       p.BeginErrorReadLine(); 
       if (outputHandler != null) p.OutputDataReceived += outputHandler; 
       if (errorHandler != null) p.ErrorDataReceived += errorHandler; 
       p.WaitForExit(); 
       p.Close(); 
       p.Dispose(); 
      } 
      catch (Exception ex) 
      { 
       log.Error(ex.Message); 
      } 
     } 
    } 

    //On another class 
    void p_ErrorDataReceived(object sender, DataReceivedEventArgs e) 
    { 
     //HANDLE STDERR 
     if (e.Data != null && !e.Data.Equals("")) 
     { 
      if (!e.Data.Contains("Something")) { 
      } 
     } 
    } 

    void p_OutputDataReceived(object sender, DataReceivedEventArgs e) 
    { 
     //HANDLE STDOUT 
     if (e.Data != null && !e.Data.Equals("")) 
     { 
     } 
    } 

    HandleExecutable he = new HandleExecutable(); 
    he.OutputHandler = p_OutputDataReceived; 
    he.ErrorHandler = p_ErrorDataReceived; 
    he.callExecutable(@"C:\java.exe","-cp foo ClassName"); 
+0

이상 적으로 읽기 전에 시작 이벤트 처리기를 설정해야합니다. 그렇지 않으면 첫 번째 출력물이 누락 될 위험이 있습니다. 예를 보려면 http://stackoverflow.com/questions/415620/redirect-console-output-to-textbox-in-separate-program-c-sharp를 참조하십시오. –

3

이러한 인수를 처리 할 셸이 없기 때문입니다. 셸에 명령 줄을 입력하면 구문 분석되고 셸 "특수"한정자에서 분리 된 프로그램 인수가 시작됩니다. C#에서는 "cmd.exe"또는 "bash"프로세스가 없으므로 이런 일이 발생하지 않습니다.

C#에서 입력을 리디렉션하려면 p.StartInfo.RedirectStandardOutput을 true로 설정하고 p.StandardOutput을 사용하여 데이터를 읽은 다음 파일에 씁니다.

또는 프로세스를 실행하고 출력을 리디렉션하는 데 필요한 매개 변수가있는 "cmd.exe"를 실행할 수 있습니다. 크로스 플랫폼이 아니더라도 효율적인 데이터 스트림 전달 구현을 직접 작성하는 것보다 쉬워야합니다.

+0

그러나 쉘을 사용하여 프로세스를 시작하려면 ProcessStartInfo.UseShellExecute를 true로 설정하십시오. 이 경우 ProcessStartInfo.UseShellExecute의 의미는 무엇입니까? 감사합니다. – Mher

+0

@Mher http://msdn.microsoft.com/en-us/library/system.diagnostics.processstartinfo.useshellexecute.aspx 등록 된 파일을 더블 클릭하거나, 또는 'start foo.doc'를 사용하여 명령 행 - 주어진 파일 유형에 쉘 처리기를 사용합니다. –

+0

도메인 사용자로 로그인 한 WindowsService 환경에서 'UseShellExecute = false'프로세스가 파일 시스템과 상호 작용할 수 없습니다. –

0

출력 스트림을 리디렉션하려면 구성해야합니다. Redirect... 속성을 설정하고 스트림을 읽습니다. 예 here을 찾을 수 있습니다.

감사합니다.

관련 문제