如何:在C#中执行命令行,获取STD OUT结果


Answers:


523
// 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


8
没有批处理文件,有没有办法做到这一点?问题是,我需要向命令发送一些参数。我正在使用xsd.exe <Assembly> / type:<ClassName>,因此我需要能够同时设置Assembly和ClassName,然后运行命令。
卡罗(Carlo)2009年

26
您可以通过{YourProcessObject}.StartInfo.Arguments字符串在呼叫中添加参数。
09年

5
如何使流程以管理员身份运行?
Saher Ahwal

5
我遇到了许多问题,由于该进程已向p.StandardError流中写入足够的数据,因此使用此代码的过程会完全停止。当流变满时,似乎进程将停止直到数据被消耗为止,因此我必须同时阅读两者StandardErrorStandardOutput以确保任务能够正确执行。
泰德·斯彭斯

5
c#编译器的快速说明:Process对象必须将UseShellExecute属性设置为false才能重定向IO流。
IbrarMumtaz 2013年

144

这是一个简单的示例:

//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
+1,用于显示如何向运行命令行程序添加参数(公认的答案没有此信息。)
Suman,

104

我发现还有一个有用的参数,可以用来消除过程窗口

pProcess.StartInfo.CreateNoWindow = true;

如果您要这么做,这有助于完全向用户隐藏黑色控制台窗口。


3
救了我很多头。谢谢。
Vivandiere 2014年

2
当调用“ sc”时,我还必须设置StartInfo.WindowStyle = ProcessWindowStyle.Hidden。
Pedro

90
// 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) +
        "'";
}

3
一个非常全面的例子,谢谢
ShahidAzim 2012年

2
可能想将OutputDataReceived处理程序更改为stdOut.AppendLine()
Paul Williams

3
我认为,这是比公认的答案更全面的解决方案。我现在正在使用它,并且还没有使用公认的,但是确实缺少它。
ProfK

1
感谢process.StartInfo.RedirectStandardError = true;if (process.ExitCode == 0)其接受的答案没有。
JohnB

12

此页面上接受的答案有一个弱点,在极少数情况下会造成麻烦。程序按约定将两个文件句柄写入stdout和stderr。如果您仅读取了一个文件句柄(例如来自Ray的答案),并且正在启动的程序将足够的输出写入stderr,它将填充输出的stderr缓冲区和块。然后,您的两个进程陷入僵局。缓冲区大小可能是4K。这在短期程序中极为罕见,但是如果您有一个长期运行的程序重复输出到stderr,则最终会发生这种情况。这很难调试和跟踪。

有两种解决此问题的好方法。

  1. 一种方法是执行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";
  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();

2
我认为这可以更好地回答原始问题,因为它显示了如何通过C#(而非文件)运行CMD命令。
TinyRacoon

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

当进程写入大量数据时,可能会死锁。最好在进程仍在运行时开始读取数据。
JensG

6

您将需要ProcessStartInfoRedirectStandardOutput启用一起使用-然后您可以读取输出流。您可能会发现使用“>”将输出重定向到文件(通过OS),然后仅读取文件会更容易。

[编辑:就像雷(Ray)一样:+1]


10
这迫使您将文件写入需要许可的位置,需要查找位置和名称,并且在完成操作后一定不要忘记删除。RedirectStandardOutput实际上更容易使用。
peSHIr

4

如果您不介意引入依赖关系,CliWrap可以为您简化此过程:

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

3

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

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


3

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


3

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

3

单线运行命令:

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


2

如果还需要在cmd.exe中执行某些命令,则可以执行以下操作:

// 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 = "cmd.exe";
p.StartInfo.Arguments = "/C vol";
p.Start();
// Read the output stream first and then wait.
string output = p.StandardOutput.ReadToEnd();
p.WaitForExit();
Console.WriteLine(output);

这仅返回命令本身的输出:

在此处输入图片说明

您也可以使用StandardInput代替StartInfo.Arguments

// Start the child process.
Process p = new Process();
// Redirect the output stream of the child process.
p.StartInfo.UseShellExecute = false;
p.StartInfo.RedirectStandardInput = true;
p.StartInfo.RedirectStandardOutput = true;
p.StartInfo.FileName = "cmd.exe";
p.Start();
// Read the output stream first and then wait.
p.StandardInput.WriteLine("vol");
p.StandardInput.WriteLine("exit");
string output = p.StandardOutput.ReadToEnd();
p.WaitForExit();
Console.WriteLine(output);

结果看起来像这样:

在此处输入图片说明


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); 
            }
    }

0

由于此处的大多数答案未实现usingstatemant IDisposable以及我认为可能是必要的其他一些东西,因此我将添加此答案。

对于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");
}
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.