我如何从c#执行命令行程序,并获得STD OUT结果?具体来说,我想对两个以编程方式选择的文件执行DIFF,并将结果写入一个文本框。


当前回答

这里有一个小例子:

using System;
using System.Diagnostics;

class Program
{
    static void Main(string[] args)
    {
        var p = Process.Start(
            new ProcessStartInfo("git", "branch --show-current")
            {
                CreateNoWindow = true,
                UseShellExecute = false,
                RedirectStandardError = true,
                RedirectStandardOutput = true,
                WorkingDirectory = Environment.CurrentDirectory
            }
        );

        p.WaitForExit();
        string branchName =p.StandardOutput.ReadToEnd().TrimEnd();
        string errorInfoIfAny =p.StandardError.ReadToEnd().TrimEnd();

        if (errorInfoIfAny.Length != 0)
        {
            Console.WriteLine($"error: {errorInfoIfAny}");
        }
        else { 
            Console.WriteLine($"branch: {branchName}");
        }

    }
}

我相信这是最短的形式。

请注意,大多数命令行工具很容易混淆标准输出和标准错误,有时将它们组合成一个字符串是有意义的。

p.e exitcode有时也很有用。

上面的例子用于编写命令行工具,如果你想自己做的话。请注意,对于cli自动化,也可以使用Cake Frosten和Cake Git扩展。

其他回答

因为这里的大多数答案都没有实现IDisposable的using语句和一些其他的东西,我认为可能是必要的,我会添加这个答案。

对于c# 8.0

// Start a process with the filename or path with filename e.g. "cmd". Please note the 
//using statemant
using myProcess.StartInfo.FileName = "cmd";
// add the arguments - Note add "/c" if you want to carry out tge  argument in cmd and  
// terminate
myProcess.StartInfo.Arguments = "/c dir";
// Allows to raise events
myProcess.EnableRaisingEvents = true;
//hosted by the application itself to not open a black cmd window
myProcess.StartInfo.UseShellExecute = false;
myProcess.StartInfo.CreateNoWindow = true;
// Eventhander for data
myProcess.Exited += OnOutputDataRecived;
// Eventhandler for error
myProcess.ErrorDataReceived += OnErrorDataReceived;
// Eventhandler wich fires when exited
myProcess.Exited += OnExited;
// Starts the process
myProcess.Start();
//read the output before you wait for exit
myProcess.BeginOutputReadLine();
// wait for the finish - this will block (leave this out if you dont want to wait for 
// it, so it runs without blocking)
process.WaitForExit();

// Handle the dataevent
private void OnOutputDataRecived(object sender, DataReceivedEventArgs e)
{
    //do something with your data
    Trace.WriteLine(e.Data);
}

//Handle the error
private void OnErrorDataReceived(object sender, DataReceivedEventArgs e)
{        
    Trace.WriteLine(e.Data);
    //do something with your exception
    throw new Exception();
}    

// Handle Exited event and display process information.
private void OnExited(object sender, System.EventArgs e)
{
     Trace.WriteLine("Process exited");
}

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

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

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

这里有一个简单的例子:

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

The accepted answer on this page has a weakness that is troublesome in rare situations. There are two file handles which programs write to by convention, stdout, and stderr. If you just read a single file handle such as the answer from Ray, and the program you are starting writes enough output to stderr, it will fill up the output stderr buffer and block. Then your two processes are deadlocked. The buffer size may be 4K. This is extremely rare on short-lived programs, but if you have a long running program which repeatedly outputs to stderr, it will happen eventually. This is tricky to debug and track down.

有一些很好的方法来处理这个问题。

One way is to execute cmd.exe instead of your program and use the /c argument to cmd.exe to invoke your program along with the "2>&1" argument to cmd.exe to tell it to merge stdout and stderr. var p = new Process(); p.StartInfo.FileName = "cmd.exe"; p.StartInfo.Arguments = "/c mycmd.exe 2>&1"; Another way is to use a programming model which reads both handles at the same time. 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();