方法:C#でコマンドラインを実行し、STD OUTの結果を取得する


472

C#からコマンドラインプログラムを実行して、STD OUTの結果を取得するにはどうすればよいですか?具体的には、プログラムで選択された2つのファイルに対してDIFFを実行し、結果をテキストボックスに書き込みます。


2
stackoverflow.com/a/5367686/492も参照してください-出力とエラーのイベントが表示されます。
CADは、2015

関連(ただしSTDOUTをキャプチャしない):stackoverflow.com/questions/1469764
user202729

回答:


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

26
{YourProcessObject}.StartInfo.Arguments文字列を使用して、呼び出しに引数を追加できます。
パトリッジ09/11/16

5
プロセスを管理者として実行するにはどうすればよいですか?
Saher Ahwal

5
プロセスが十分なデータをp.StandardErrorストリームに書き込んだため、このコードを使用するプロセスが完全に停止するという問題がいくつか発生しました。ストリームが満杯になると、データが消費されるまで、私は両方を読み取るために持っているので、プロセスは、停止しますことが表示されますStandardErrorStandardOutput、タスクが正しく実行されることを保証するために。
テッドスペンス

5
C#コンパイラからのクイックヘッドサップ:IOストリームをリダイレクトするには、ProcessオブジェクトのUseShellExecuteプロパティをfalseに設定する必要があります。
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

プロセスウィンドウを削除するために使用できる他のパラメーターが1つあります。

pProcess.StartInfo.CreateNoWindow = true;

これにより、必要に応じて、黒いコンソールウィンドウをユーザーから完全に隠すことができます。


3
頭痛の種をたくさん救いました。ありがとう。
Vivandiere 2014

2
"sc"を呼び出すとき、StartInfo.WindowStyle = ProcessWindowStyle.Hiddenも設定する必要がありました。
ペドロ14

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 2015年

1
ありがとう、process.StartInfo.RedirectStandardError = true;そしてif (process.ExitCode == 0)受け入れられた答えはありません。
JohnB

12

このページで受け入れられた回答には、まれな状況で問題となる弱点があります。プログラムが標準で書き込むファイルハンドルには、標準出力と標準エラー出力の2つがあります。Rayからの回答などの単一のファイルハンドルを読み取るだけで、開始するプログラムがstderrに十分な出力を書き込むと、出力stderrバッファーとブロックがいっぱいになります。次に、2つのプロセスがデッドロックします。バッファサイズは4Kです。これは、存続期間の短いプログラムでは非常にまれですが、stderrに繰り返し出力する長期実行プログラムがある場合、最終的には発生します。これはデバッグして追跡するのが難しいです。

これに対処するにはいくつかの良い方法があります。

  1. 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経由で)出力をファイルにリダイレクトし、ファイルを読み取る方が簡単な場合があります。

[編集:レイがしたことのように:+1]


10
そのため、アクセス許可が必要な場所にファイルを書き込む必要があり、場所と名前を見つける必要があります。ファイルを使い終わったら、忘れずに削除してください。RedirectStandardOutput実際に使いやすい。
peSHIr 2009年

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プロパティを設定できます。プロセスが完了したら、そのストリームで必要なdiffを実行できます。


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

ここでのほとんどの回答は、statemantを実装していないusingため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");
}
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.