2008-10-15 90 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); 
      } 
    }