How To: Execute command line in C#, get STD OUT results
如何从C执行命令行程序并返回std out结果?具体来说,我想对两个以编程方式选择的文件执行diff,并将结果写入文本框。
1 2 3 4 5 6 7 8 9 10 11 12 13 | // 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。
下面是一个快速的示例:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 | //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(); |
还有一个我发现有用的参数,我用它来消除进程窗口
1 | pProcess.StartInfo.CreateNoWindow = true; |
这有助于对用户完全隐藏黑色控制台窗口(如果您希望这样做的话)。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 | // 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 2 3 4 5 6 7 8 9 10 11 12 | 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(); } |
本页接受的答案有一个弱点,在极少数情况下很麻烦。有两个文件句柄,程序按约定写入,stdout和stderr。如果您只是读取一个文件句柄(如来自ray的应答),并且您正在启动的程序将足够的输出写入stderr,那么它将填充输出stderr缓冲区和块。然后您的两个进程就死锁了。缓冲区大小可以是4K。这在短期程序中非常罕见,但是如果有一个长时间运行的程序反复输出到stderr,它最终会发生。这很难调试和跟踪。
有两种很好的方法来解决这个问题。
一种方法是执行cmd.exe而不是您的程序,并使用cmd.exe的/c参数来调用您的程序,同时使用cmd.exe的"2>&;1"参数来告诉它合并stdout和stderr。
1 2 3 |
另一种方法是使用同时读取两个句柄的编程模型。
1 2 3 4 5 6 7 8 9 10 11 12 13 | 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(); |
您需要在启用
[编辑:就像雷做的那样:+1]
如果您不介意引入依赖项,cliwrap可以为您简化这一过程:
1 2 3 | var cli = new Cli("target.exe"); var output = await cli.ExecuteAsync("arguments","stdin"); var stdout = output.StandardOutput; |
如果您试图查询PC/服务器上的本地ARP缓存,这可能对某些人有用。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 | 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(); } |
可以使用进程类启动任何命令行程序,并使用创建的流读取器(基于字符串或内存位置)设置进程实例的StandardOutput属性。在流程完成后,您可以在该流上执行任何需要的差异。
这可能不是最好/最简单的方法,但可能是一个选项:
从代码执行时,添加">output.txt",然后读取output.txt文件。
PublicDomain开放源代码中有一个ProcessHelper类,您可能会感兴趣。
为了好玩,这里是我完成的关于获取python输出的解决方案-在按钮点击下-带有错误报告。只需添加一个名为"Butpython"的按钮和一个名为"llhello"的标签…
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 | 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); } } |