Comment exécuter un programme de ligne de commande à partir de C # et récupérer les résultats STD OUT? Plus précisément, je veux exécuter DIFF sur deux fichiers sélectionnés par programme et écrire les résultats dans une zone de texte.
Comment exécuter un programme de ligne de commande à partir de C # et récupérer les résultats STD OUT? Plus précisément, je veux exécuter DIFF sur deux fichiers sélectionnés par programme et écrire les résultats dans une zone de texte.
Réponses:
// 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();
Le code provient de MSDN .
{YourProcessObject}.StartInfo.Arguments
chaîne.
p.StandardError
flux. Lorsque le flux est plein, il semble que le processus s'arrête jusqu'à ce que les données soient consommées, je dois donc lire les deux StandardError
et StandardOutput
afin de garantir qu'une tâche s'exécute correctement.
Voici un petit échantillon:
//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();
Il y a un autre paramètre que j'ai trouvé utile, que j'utilise pour éliminer la fenêtre de processus
pProcess.StartInfo.CreateNoWindow = true;
cela aide à cacher complètement la fenêtre de console noire à l'utilisateur, si c'est ce que vous désirez.
// 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;
et if (process.ExitCode == 0)
quelle réponse acceptée n'a pas.
La réponse acceptée sur cette page présente une faiblesse gênante dans de rares situations. Il existe deux descripteurs de fichiers sur lesquels les programmes écrivent par convention, stdout et stderr. Si vous venez de lire un seul descripteur de fichier tel que la réponse de Ray, et que le programme que vous démarrez écrit suffisamment de sortie dans stderr, il remplira le tampon et le bloc de sortie stderr. Vos deux processus sont alors bloqués. La taille du tampon peut être 4K. C'est extrêmement rare sur les programmes de courte durée, mais si vous avez un programme de longue durée qui sort à plusieurs reprises sur stderr, cela se produira éventuellement. C'est difficile à déboguer et à retrouver.
Il y a quelques bonnes façons de gérer cela.
Une façon consiste à exécuter cmd.exe au lieu de votre programme et à utiliser l'argument / c à cmd.exe pour appeler votre programme avec l'argument "2> & 1" à cmd.exe pour lui dire de fusionner stdout et stderr.
var p = new Process();
p.StartInfo.FileName = "cmd.exe";
p.StartInfo.Arguments = "/c mycmd.exe 2>&1";
Une autre façon consiste à utiliser un modèle de programmation qui lit les deux poignées en même temps.
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();
}
Vous devrez utiliser ProcessStartInfo
avec RedirectStandardOutput
activé - alors vous pouvez lire le flux de sortie. Vous trouverez peut-être plus facile d'utiliser ">" pour rediriger la sortie vers un fichier (via le système d'exploitation), puis de simplement lire le fichier.
[modifier: comme ce que Ray a fait: +1]
RedirectStandardOutput
fait.
Vous pouvez lancer n'importe quel programme de ligne de commande à l'aide de la classe Process et définir la propriété StandardOutput de l'instance Process avec un lecteur de flux que vous créez (en fonction d'une chaîne ou d'un emplacement mémoire). Une fois le processus terminé, vous pouvez alors faire tout ce dont vous avez besoin sur ce flux.
Cela peut être utile pour quelqu'un si vous essayez d'interroger le cache ARP local sur un PC / serveur.
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();
}
Commande d'exécution sur une ligne:
new Process() { StartInfo = new ProcessStartInfo("echo", "Hello, World") }.Start();
Lire la sortie de la commande dans la plus petite quantité de code disponible:
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();
Il existe une classe ProcessHelper dans le code open source PublicDomain qui pourrait vous intéresser.
Si vous devez également exécuter une commande dans cmd.exe, vous pouvez effectuer les opérations suivantes:
// 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);
Cela renvoie uniquement la sortie de la commande elle-même:
Vous pouvez également utiliser à la StandardInput
place de 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);
Le résultat ressemble à ceci:
Juste pour le plaisir, voici ma solution complète pour obtenir une sortie PYTHON - sous un clic de bouton - avec un rapport d'erreur. Ajoutez simplement un bouton appelé "butPython" et une étiquette appelée "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);
}
}
Étant donné que la plupart des réponses ici using
n'implémentent pas le statemant pour IDisposable
et d'autres choses qui, je pense, pourraient être nécessaires, j'ajouterai cette réponse.
Pour 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");
}