2008-10-15 89 views
397

如何從C#執行命令行程序並取回STD OUT結果。具體來說,我想對以編程方式選擇的兩個文件執行DIFF,並將結果寫入文本框。是的,我可以算出來爲自己,但肯定別人做類似的東西,我懶...如何:在C#中執行命令行,獲取STD OUT結果

+2

也http://stackoverflow.com/a/5367686/492看到的 - 它顯示輸出和錯誤事件。 – 2015-08-17 00:37:01

回答

448
// Start the child process. 
Process p = new Process(); 
// Redirect the output stream of the child process. 
p.StartInfo.UseShellExecute = false; 
p.StartInfo.RedirectStandardOutput = true; 
p.StartInfo.FileName = "YOURBATCHFILE.bat"; 
p.Start(); 
// Do not wait for the child process to exit before 
// reading to the end of its redirected stream. 
// p.WaitForExit(); 
// Read the output stream first and then wait. 
string output = p.StandardOutput.ReadToEnd(); 
p.WaitForExit(); 

代碼是從MSDN

+203

當您在其他地方剪切粘貼代碼時,習慣上添加一個屬性。這是取自http://msdn.microsoft.com/en-us/library/system.diagnostics.process.standardoutput.aspx – 2009-03-04 08:14:16

+5

有沒有辦法做到這一點沒有批處理文件?事情是,我需要發送一些參數給命令。我正在使用xsd.exe /type:,所以我需要能夠設置Assembly和ClassName,然後運行該命令。 – Carlo 2009-10-09 17:43:32

+22

您可以通過`{YourProcessObject} .StartInfo.Arguments`字符串爲您的調用添加參數。 – patridge 2009-11-16 17:34:19

4

這可能不是最好/最簡單的方法,但可能是一種選擇:

從代碼執行時,添加「> output.txt」,然後讀取output.txt文件。

7

您需要使用ProcessStartInfo並啓用RedirectStandardOutput - 然後才能讀取輸出流。您可能會發現使用「>」將輸出重定向到文件(通過操作系統)更容易,然後只需讀取該文件即可。

[編輯:喜歡什麼雷那樣:+1]

4

您可以使用Process類啓動任何命令行程序,並與您共創一個流讀取器設置流程實例的StandardOutput財產(無論是基於一個字符串或一個內存位置)。過程完成後,您可以在該流上執行任何所需的差異。

13
System.Diagnostics.ProcessStartInfo psi = 
    new System.Diagnostics.ProcessStartInfo(@"program_to_call.exe"); 
psi.RedirectStandardOutput = true; 
psi.WindowStyle = System.Diagnostics.ProcessWindowStyle.Hidden; 
psi.UseShellExecute = false; 
System.Diagnostics.Process proc System.Diagnostics.Process.Start(psi);; 
System.IO.StreamReader myOutput = proc.StandardOutput; 
proc.WaitForExit(2000); 
if (proc.HasExited) 
    { 
    string output = myOutput.ReadToEnd(); 
} 
119

下面是一個簡單示例:

//Create process 
System.Diagnostics.Process pProcess = new System.Diagnostics.Process(); 

//strCommand is path and file name of command to run 
pProcess.StartInfo.FileName = strCommand; 

//strCommandParameters are parameters to pass to program 
pProcess.StartInfo.Arguments = strCommandParameters; 

pProcess.StartInfo.UseShellExecute = false; 

//Set output of program to be written to process output stream 
pProcess.StartInfo.RedirectStandardOutput = true; 

//Optional 
pProcess.StartInfo.WorkingDirectory = strWorkingDirectory; 

//Start the process 
pProcess.Start(); 

//Get program output 
string strOutput = pProcess.StandardOutput.ReadToEnd(); 

//Wait for process to finish 
pProcess.WaitForExit(); 
2

有一個ProcessHelper類中PublicDomain開放源代碼,你可能會感興趣。

89

還有一個其他參數,我發現有用的,這是我用來消除工藝窗口

pProcess.StartInfo.CreateNoWindow = true; 

這有助於完全隱藏用戶的黑色控制檯窗口,如果這是你的願望。

70
// usage 
const string ToolFileName = "example.exe"; 
string output = RunExternalExe(ToolFileName); 

public string RunExternalExe(string filename, string arguments = null) 
{ 
    var process = new Process(); 

    process.StartInfo.FileName = filename; 
    if (!string.IsNullOrEmpty(arguments)) 
    { 
     process.StartInfo.Arguments = arguments; 
    } 

    process.StartInfo.CreateNoWindow = true; 
    process.StartInfo.WindowStyle = ProcessWindowStyle.Hidden; 
    process.StartInfo.UseShellExecute = false; 

    process.StartInfo.RedirectStandardError = true; 
    process.StartInfo.RedirectStandardOutput = true; 
    var stdOutput = new StringBuilder(); 
    process.OutputDataReceived += (sender, args) => stdOutput.AppendLine(args.Data); // Use AppendLine rather than Append since args.Data is one line of output, not including the newline character. 

    string stdError = null; 
    try 
    { 
     process.Start(); 
     process.BeginOutputReadLine(); 
     stdError = process.StandardError.ReadToEnd(); 
     process.WaitForExit(); 
    } 
    catch (Exception e) 
    { 
     throw new Exception("OS error while executing " + Format(filename, arguments)+ ": " + e.Message, e); 
    } 

    if (process.ExitCode == 0) 
    { 
     return stdOutput.ToString(); 
    } 
    else 
    { 
     var message = new StringBuilder(); 

     if (!string.IsNullOrEmpty(stdError)) 
     { 
      message.AppendLine(stdError); 
     } 

     if (stdOutput.Length != 0) 
     { 
      message.AppendLine("Std output:"); 
      message.AppendLine(stdOutput.ToString()); 
     } 

     throw new Exception(Format(filename, arguments) + " finished with exit code = " + process.ExitCode + ": " + message); 
    } 
} 

private string Format(string filename, string arguments) 
{ 
    return "'" + filename + 
     ((string.IsNullOrEmpty(arguments)) ? string.Empty : " " + arguments) + 
     "'"; 
} 
1

如果您試圖查詢PC/Server上的本地ARP緩存,這可能對某人有用。

List<string[]> results = new List<string[]>(); 

     using (Process p = new Process()) 
     { 
      p.StartInfo.CreateNoWindow = true; 
      p.StartInfo.RedirectStandardOutput = true; 
      p.StartInfo.UseShellExecute = false; 
      p.StartInfo.Arguments = "/c arp -a"; 
      p.StartInfo.FileName = @"C:\Windows\System32\cmd.exe"; 
      p.Start(); 

      string line; 

      while ((line = p.StandardOutput.ReadLine()) != null) 
      { 
       if (line != "" && !line.Contains("Interface") && !line.Contains("Physical Address")) 
       { 
        var lineArr = line.Trim().Split(' ').Select(n => n).Where(n => !string.IsNullOrEmpty(n)).ToArray(); 
        var arrResult = new string[] 
       { 
        lineArr[0], 
        lineArr[1], 
        lineArr[2] 
       }; 
        results.Add(arrResult); 
       } 
      } 

      p.WaitForExit(); 
     } 
2

如果你不介意引進的依賴,CliWrap可以簡化這個給你:

var cli = new Cli("target.exe"); 
var output = await cli.ExecuteAsync("arguments", "stdin"); 
var stdout = output.StandardOutput; 
1

此頁面上接受的答案有一個弱點就是在罕見的情況下麻煩。有兩個文件句柄,程序按慣例寫入,stdout和stderr。 如果您只是讀取一個單獨的文件句柄,例如Ray的答案,並且您正在開始的程序將足夠的輸出寫入stderr,它將填充輸出stderr緩衝區和塊。然後你的兩個進程陷入僵局。緩衝區大小可能是4K。 對於短命的程序來說,這是非常罕見的,但是如果你有一個長時間運行的程序重複輸出到stderr,它最終會發生。這很難調試和追蹤。

有幾個很好的方法來處理這個問題。

  1. 的一種方法是執行,而不是你的程序的cmd.exe和使用/ c參數對cmd.exe的與「2> & 1」的說法沿着調用你的程序對cmd.exe的告訴它合併stdout和stderr。

     var p = new Process(); 
         p.StartInfo.FileName = "cmd.exe"; 
         p.StartInfo.Arguments = "/c mycmd.exe 2>&1"; 
    
  2. 另一種方法是使用同時讀取兩個手柄的編程模型。

     var p = new Process(); 
         p.StartInfo.FileName = "cmd.exe"; 
         p.StartInfo.Arguments = @"/c dir \windows"; 
         p.StartInfo.CreateNoWindow = true; 
         p.StartInfo.RedirectStandardError = true; 
         p.StartInfo.RedirectStandardOutput = true; 
         p.StartInfo.RedirectStandardInput = false; 
         p.OutputDataReceived += (a, b) => Console.WriteLine(b.Data); 
         p.ErrorDataReceived += (a, b) => Console.WriteLine(b.Data); 
         p.Start(); 
         p.BeginErrorReadLine(); 
         p.BeginOutputReadLine(); 
         p.WaitForExit(); 
    
0

只是爲了好玩,這是我爲獲得PYTHON輸出完整的解決方案 - 點擊一個按鈕下 - 與錯誤報告。只需添加一個名爲「butPython」按鈕,一個名爲「llHello」標籤...

private void butPython(object sender, EventArgs e) 
    { 
     llHello.Text = "Calling Python..."; 
     this.Refresh(); 
     Tuple<String,String> python = GoPython(@"C:\Users\BLAH\Desktop\Code\Python\BLAH.py"); 
     llHello.Text = python.Item1; // Show result. 
     if (python.Item2.Length > 0) MessageBox.Show("Sorry, there was an error:" + Environment.NewLine + python.Item2); 
    } 

    public Tuple<String,String> GoPython(string pythonFile, string moreArgs = "") 
    { 
     ProcessStartInfo PSI = new ProcessStartInfo(); 
     PSI.FileName = "py.exe"; 
     PSI.Arguments = string.Format("\"{0}\" {1}", pythonFile, moreArgs); 
     PSI.CreateNoWindow = true; 
     PSI.UseShellExecute = false; 
     PSI.RedirectStandardError = true; 
     PSI.RedirectStandardOutput = true; 
     using (Process process = Process.Start(PSI)) 
      using (StreamReader reader = process.StandardOutput) 
      { 
       string stderr = process.StandardError.ReadToEnd(); // Error(s)!! 
       string result = reader.ReadToEnd(); // What we want. 
       return new Tuple<String,String> (result,stderr); 
      } 
    }