C#からコマンドラインプログラムを実行してSTD OUTの結果を返すにはどうすればよいですか?具体的には、プログラムで選択された2つのファイルに対してDIFFを実行し、その結果をテキストボックスに書き込みます。
// 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 _ からです。
これが簡単なサンプルです。
//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();
プロセスウィンドウを削除するために私が使用した、私が有用だと思うもう一つのパラメータがあります。
pProcess.StartInfo.CreateNoWindow = true;
それがあなたが望むものであるなら、これはユーザーから完全に黒いコンソールウィンドウを隠すのを助けます。
// 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) +
"'";
}
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();
}
このページで受け入れられている答えは弱点があり、まれな状況では面倒です。プログラムが規約に従って書き込むファイルハンドルは、stdoutとstderrの2つです。 Rayからの回答のように1つのファイルハンドルを読み、開始しているプログラムがstderrに十分な出力を書き込むと、それは出力stderrバッファとブロックをいっぱいにします。その後、あなたの2つのプロセスは行き詰まります。バッファサイズは4Kです。これは短期間のプログラムでは非常にまれですが、stderrに繰り返し出力する長時間実行されるプログラムがあると、やがて起こります。これはデバッグや追跡が難しいです。
これに対処するための良い方法がいくつかあります。
1つの方法は、プログラムの代わりにcmd.exeを実行し、cmd.exeの/ 2引数とcmd.exeの "2>&1"引数を組み合わせてstdoutとstderrをマージするように指示することです。
var p = new Process();
p.StartInfo.FileName = "cmd.exe";
p.StartInfo.Arguments = "/c mycmd.exe 2>&1";
もう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();
ProcessStartInfo
を有効にしてRedirectStandardOutput
を使用する必要があります - それから出力ストリームを読むことができます。 ">"を使って(OS経由で)出力をファイルにリダイレクトしてから、単にそのファイルを読むほうが簡単なことがあります。
[編集:Rayがやったように:+1]
依存関係を導入しても構わない場合は、 CliWrap を使用すると簡単になります。
var cli = new Cli("target.exe");
var output = await cli.ExecuteAsync("arguments", "stdin");
var stdout = output.StandardOutput;
これは最善/最も簡単な方法ではないかもしれませんが、オプションであるかもしれません:
コードから実行するときは、 "> output.txt"を追加してからoutput.txtファイルを読みます。
Processクラスを使用して任意のコマンドラインプログラムを起動し、作成したストリームリーダーを使用してProcessインスタンスのStandardOutputプロパティを設定できます(文字列またはメモリの場所に基づく)。プロセスが完了したら、そのストリームに対して必要な差分をすべて実行できます。
あなたが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();
}
PublicDomain オープンソースコードにProcessHelperクラスがあります。
念のために、ここにボタンをクリックするだけで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);
}
}