Wie führe ich ein Befehlszeilenprogramm von C # aus und erhalte die STD OUT-Ergebnisse zurück? Insbesondere möchte ich DIFF für zwei Dateien ausführen, die programmgesteuert ausgewählt wurden, und die Ergebnisse in ein Textfeld schreiben.
Wie führe ich ein Befehlszeilenprogramm von C # aus und erhalte die STD OUT-Ergebnisse zurück? Insbesondere möchte ich DIFF für zwei Dateien ausführen, die programmgesteuert ausgewählt wurden, und die Ergebnisse in ein Textfeld schreiben.
Antworten:
// 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();
Der Code stammt von MSDN .
{YourProcessObject}.StartInfo.Arguments
Zeichenfolge Argumente hinzufügen .
p.StandardError
Stream geschrieben hat. Wenn der Stream voll ist, scheint der Prozess anzuhalten, bis die Daten verbraucht sind. Daher muss ich beide lesen StandardError
und StandardOutput
sicherstellen, dass eine Aufgabe korrekt ausgeführt wird.
Hier ist ein kurzes Beispiel:
//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();
Dort fand ich einen weiteren Parameter nützlich, mit dem ich das Prozessfenster eliminiere
pProcess.StartInfo.CreateNoWindow = true;
Dies hilft, das schwarze Konsolenfenster vollständig vor dem Benutzer zu verbergen, wenn Sie dies wünschen.
// 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;
und if (process.ExitCode == 0)
welche akzeptierte Antwort hat nicht.
Die akzeptierte Antwort auf dieser Seite weist eine Schwäche auf, die in seltenen Situationen problematisch ist. Es gibt zwei Dateihandles, in die Programme gemäß Konvention schreiben: stdout und stderr. Wenn Sie nur ein einzelnes Dateihandle wie die Antwort von Ray lesen und das Programm, das Sie starten, genügend Ausgabe in stderr schreibt, füllt es den Ausgabe-Stderr-Puffer und -Block. Dann sind Ihre beiden Prozesse festgefahren. Die Puffergröße kann 4 KB betragen. Dies ist bei kurzlebigen Programmen äußerst selten, aber wenn Sie ein lang laufendes Programm haben, das wiederholt an stderr ausgegeben wird, wird es irgendwann passieren. Dies ist schwierig zu debuggen und aufzuspüren.
Es gibt ein paar gute Möglichkeiten, damit umzugehen.
Eine Möglichkeit besteht darin, cmd.exe anstelle Ihres Programms auszuführen und das Argument / c für cmd.exe zu verwenden, um Ihr Programm zusammen mit dem Argument "2> & 1" für cmd.exe aufzurufen, damit stdout und stderr zusammengeführt werden.
var p = new Process();
p.StartInfo.FileName = "cmd.exe";
p.StartInfo.Arguments = "/c mycmd.exe 2>&1";
Eine andere Möglichkeit besteht darin, ein Programmiermodell zu verwenden, das beide Handles gleichzeitig liest.
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();
}
Sie müssen ProcessStartInfo
mit RedirectStandardOutput
aktiviert verwenden - dann können Sie den Ausgabestream lesen. Möglicherweise ist es einfacher, ">" zu verwenden, um die Ausgabe in eine Datei umzuleiten (über das Betriebssystem) und dann einfach die Datei zu lesen.
[bearbeiten: wie Ray es getan hat: +1]
RedirectStandardOutput
.
Wenn es Ihnen nichts ausmacht, eine Abhängigkeit einzuführen, kann CliWrap dies für Sie vereinfachen:
var cli = new Cli("target.exe");
var output = await cli.ExecuteAsync("arguments", "stdin");
var stdout = output.StandardOutput;
Sie können jedes Befehlszeilenprogramm mit der Process-Klasse starten und die StandardOutput-Eigenschaft der Process-Instanz mit einem von Ihnen erstellten Stream-Reader festlegen (entweder basierend auf einer Zeichenfolge oder einem Speicherort). Nachdem der Vorgang abgeschlossen ist, können Sie alle erforderlichen Änderungen an diesem Stream vornehmen.
Dies kann für jemanden nützlich sein, wenn Sie versuchen, den lokalen ARP-Cache auf einem PC / Server abzufragen.
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();
}
Einzeiliger Ausführungsbefehl:
new Process() { StartInfo = new ProcessStartInfo("echo", "Hello, World") }.Start();
Lesen Sie die Ausgabe des Befehls in kürzester Menge des Reable-Codes:
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();
In PublicDomain Open Source Code gibt es eine ProcessHelper-Klasse, die Sie interessieren könnte.
Falls Sie auch einen Befehl in der cmd.exe ausführen müssen, können Sie Folgendes tun:
// 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);
Dies gibt nur die Ausgabe des Befehls selbst zurück:
Sie können auch StandardInput
anstelle von 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);
Das Ergebnis sieht folgendermaßen aus:
Nur zum Spaß, hier ist meine fertige Lösung, um PYTHON-Ausgabe - mit einem Klick auf eine Schaltfläche - mit Fehlerberichterstattung zu erhalten. Fügen Sie einfach eine Schaltfläche namens "butPython" und eine Bezeichnung namens "llHello" hinzu ...
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);
}
}
Da die meisten Antworten hier implementieren nicht den using
statemant für IDisposable
und einige andere Sachen Wich ich denken konnte nessecary sein ich diese Antwort hinzufügen.
Für 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");
}