首页 文章

操作方法:在C#中执行命令行,获取STD OUT结果

提问于
浏览
420

如何从C#执行命令行程序并返回STD OUT结果 . 具体来说,我想对以编程方式选择的两个文件执行DIFF,并将结果写入文本框 . 是的,我可以为自己解决这个问题,但肯定有人做过类似的事情,我很懒...

13 回答

  • 468
    // 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 .

  • 0

    这是一个快速示例:

    //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();
    
  • 92

    还有一个我发现有用的参数,我用它来消除进程窗口

    pProcess.StartInfo.CreateNoWindow = true;
    

    这有助于完全隐藏黑色控制台窗口,如果这是你想要的 .

  • 3
    // 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) +
            "'";
    }
    
  • 4
    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();
     }
    
  • 4

    您将需要使用 ProcessStartInfo 并启用 RedirectStandardOutput - 然后您可以读取输出流 . 您可能会发现使用">"将输出重定向到文件(通过操作系统)更容易,然后只需读取文件即可 .

    [编辑:像雷一样:1]

  • 7

    这可能不是最好/最简单的方法,但可能是一个选项:

    从代码执行时,添加“> output.txt”,然后读入output.txt文件 .

  • 13

    您可以使用Process类启动任何命令行程序,并使用您创建的流阅读器设置Process实例的StandardOutput属性(基于字符串或内存位置) . 在该过程完成后,您可以在该流上执行您需要的任何差异 .

  • 76

    此页面上接受的答案有一个在极少数情况下很麻烦的弱点 . 有两个文件句柄,程序按惯例,stdout和stderr写入 . 如果您只是读取单个文件句柄(例如Ray的答案),并且您正在开始的程序将足够的输出写入stderr,它将填充输出stderr缓冲区并阻塞 . 然后你的两个进程陷入僵局 . 缓冲区大小可以是4K . 这在短期程序中极为罕见,但如果你有一个长期运行的程序,它反复输出到stderr,它最终会发生 . 调试和跟踪这很棘手 .

    有几种很好的方法可以解决这个问题 .

    • 一种方法是执行cmd.exe而不是程序,并使用cmd.exe的/ c参数调用程序以及cmd.exe的“2>&1”参数,告诉它合并stdout和stderr .
    var p = new Process();
            p.StartInfo.FileName = "cmd.exe";
            p.StartInfo.Arguments = "/c mycmd.exe 2>&1";
    
    • 另一种方法是使用一个同时读取两个句柄的编程模型 .
    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();
    
  • 2

    如果您不介意引入依赖项,CliWrap可以为您简化:

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

    PublicDomain开源代码中有一个ProcessHelper类,您可能会感兴趣 .

  • 4

    如果您尝试在PC /服务器上查询本地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();
            }
    
  • 128

    只是为了好玩,这是我完成的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); 
                }
        }
    

相关问题