Як виконати програму командного рядка з C # та повернути результати STD OUT? Зокрема, я хочу виконати DIFF на двох файлах, які вибираються програмно, і записати результати у текстове поле.
Як виконати програму командного рядка з C # та повернути результати STD OUT? Зокрема, я хочу виконати 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 .
{YourProcessObject}.StartInfo.Arguments
рядок.
p.StandardError
потік. Коли потік стає повним, виявляється, що процес зупинятиметься, поки дані не будуть використані, тому я повинен прочитати і те, StandardError
і StandardOutput
щоб гарантувати, що завдання виконується правильно.
Ось короткий зразок:
//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) +
"'";
}
process.StartInfo.RedirectStandardError = true;
і if (process.ExitCode == 0)
прийняв відповідь не має.
Прийнята відповідь на цій сторінці має слабкість, яка турбує у рідкісних ситуаціях. Є дві ручки файлів, на які програми записуються за умовами, stdout та stderr. Якщо ви просто прочитаєте одну ручку файлу, таку як відповідь від Ray, і програма, яку ви запускаєте, записує достатню кількість вихідних даних у stderr, вона заповнить вихідний буфер і блокувати stderr. Тоді ваші два процеси заходять у тупик. Розмір буфера може бути 4К. Це вкрай рідко в короткотривалих програмах, але якщо у вас є тривала програма, яка неодноразово виводиться на більш жорстку, це відбудеться з часом. Це складно налагоджувати та відстежувати.
Є кілька хороших способів впоратися з цим.
Одним із способів є виконання cmd.exe замість програми та використання аргументу / c для cmd.exe для виклику вашої програми разом із аргументом "2> & 1" до cmd.exe, щоб сказати їй об'єднати stdout та stderr.
var p = new Process();
p.StartInfo.FileName = "cmd.exe";
p.StartInfo.Arguments = "/c mycmd.exe 2>&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();
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();
}
Вам потрібно буде використовувати ProcessStartInfo
з RedirectStandardOutput
включеним - тоді ви зможете прочитати вихідний потік. Можливо, вам буде простіше використовувати ">" для перенаправлення виводу у файл (через ОС), а потім просто прочитати файл.
[редагувати: як те, що зробив Рей: +1]
RedirectStandardOutput
насправді.
Ви можете запустити будь-яку програму командного рядка за допомогою класу Process і встановити властивість StandardOutput екземпляра Process за допомогою створеного зчитувача потоків (на основі рядка або місця пам'яті). Після завершення процесу ви зможете робити все необхідне для цього потоку.
Це може бути корисно для когось, якщо ви намагаєтеся запитати локальний кеш 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();
}
Команда запуску з одного лайнера:
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();
У відкритому вихідному коді PublicDomain існує клас ProcessHelper, який може вас зацікавити.
Якщо вам також потрібно виконати якусь команду в 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);
Результат виглядає приблизно так:
Для задоволення, ось моє завершене рішення для отримання виводу 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);
}
}
Оскільки більшість відповідей тут Dont реалізувати using
statemant для IDisposable
і деяких інших речей яким я думаю , що може бути nessecary я додам цю відповідь.
Для 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");
}