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


当前回答

因为这里的大多数答案都没有实现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");
}

其他回答

这里有一个简单的例子:

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

朱利安的解决方案经过了一些小的修正。下面是一个同样使用https://sourceforge.net/projects/bat-to-exe/ GenericConsole.cs和https://www.codeproject.com/Articles/19225/Bat-file-compiler program.txt作为args部分的例子:

using System;
using System.Text;  //StringBuilder
using System.Diagnostics;
using System.IO;


class Program
{
    private static bool redirectStandardOutput = true;

    private static string buildargument(string[] args)
    {
        StringBuilder arg = new StringBuilder();
        for (int i = 0; i < args.Length; i++)
        {
            arg.Append("\"" + args[i] + "\" ");
        }

        return arg.ToString();
    }

    static void Main(string[] args)
    {
        Process prc = new Process();
        prc.StartInfo = //new ProcessStartInfo("cmd.exe", String.Format("/c \"\"{0}\" {1}", Path.Combine(Environment.CurrentDirectory, "mapTargetIDToTargetNameA3.bat"), buildargument(args)));
        //new ProcessStartInfo(Path.Combine(Environment.CurrentDirectory, "mapTargetIDToTargetNameA3.bat"), buildargument(args));
        new ProcessStartInfo("mapTargetIDToTargetNameA3.bat");
        prc.StartInfo.Arguments = buildargument(args);

        prc.EnableRaisingEvents = true;

        if (redirectStandardOutput == true)
        {
            prc.StartInfo.UseShellExecute = false;
        }
        else
        {
            prc.StartInfo.UseShellExecute = true;
        }

        prc.StartInfo.CreateNoWindow = true;

        prc.OutputDataReceived += OnOutputDataRecived;
        prc.ErrorDataReceived += OnErrorDataReceived;
        //prc.Exited += OnExited;

        prc.StartInfo.RedirectStandardOutput = redirectStandardOutput;
        prc.StartInfo.RedirectStandardError = redirectStandardOutput;

        try
        {
            prc.Start();
            prc.BeginOutputReadLine();
            prc.BeginErrorReadLine();
            prc.WaitForExit();
        }
        catch (Exception e)
        {
            Console.WriteLine("OS error: " + e.Message);
        }

        prc.Close();
    }

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

    //Handle the error
    private static void OnErrorDataReceived(object sender, DataReceivedEventArgs e)
    {
        Console.WriteLine(e.Data);
    }

    // Handle Exited event and display process information.
    //private static void OnExited(object sender, System.EventArgs e)
    //{
    //    var process = sender as Process;
    //    if (process != null)
    //    {
    //        Console.WriteLine("ExitCode: " + process.ExitCode);
    //    }
    //    else
    //    {
    //        Console.WriteLine("Process exited");
    //    }
    //}
}

代码需要在VS2007内部编译,使用命令行csc.exe生成的可执行文件将不能正确显示控制台输出,甚至崩溃与CLR20r3错误。注释掉OnExited事件过程,蝙蝠到exe的控制台输出将更像原来的蝙蝠控制台输出。

一行运行命令:

new Process() { StartInfo = new ProcessStartInfo("echo", "Hello, World") }.Start();

以最短的可读代码量读取命令输出:

    var cliProcess = new Process() {
        StartInfo = new ProcessStartInfo("echo", "Hello, World") {
            UseShellExecute = false,
            RedirectStandardOutput = true
        }
    };
    cliProcess.Start();
    string cliOut = cliProcess.StandardOutput.ReadToEnd();
    cliProcess.WaitForExit();
    cliProcess.Close();

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

如果您试图查询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();
        }