Jak wykonać program wiersza poleceń z C# i odzyskać wyniki STD OUT. W szczególności chcę wykonać DIFF na dwóch plikach, które są programowo wybrane i zapisać wyniki w polu tekstowym. Tak, mogę dowiedzieć się tego dla siebie, ale na pewno ktoś inny zrobił coś podobnego, a ja jestem leniwy ...Jak: Uruchom polecenie w języku C#, uzyskać wyniki STD OUT
Odpowiedz
// 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();
Kod jest z MSDN.
Jest zwyczajowo dodawać atrybucję po wycięciu i wklejeniu kodu gdzie indziej. To zostało zrobione z http://msdn.microsoft.com/en-us/library/system.diagnostics.process.standardoutput.aspx –
Czy jest jakiś sposób, aby to zrobić bez pliku wsadowego? Chodzi o to, że muszę wysłać pewne parametry do polecenia. Używam xsd.exe
Możesz dodać argumenty do swojego połączenia za pomocą łańcucha '{YourProcessObject} .StartInfo.Arguments'. – patridge
To może nie być najlepszy/Najprostszym sposobem, ale może być opcja:
Po uruchomieniu z kodu dodaj "> output.txt", a następnie odczytaj w pliku output.txt.
Musisz użyć ProcessStartInfo
z włączoną opcją RedirectStandardOutput
- wtedy możesz odczytać strumień wyjściowy. Możesz łatwiej użyć ">", aby przekierować wyjście do pliku (przez system operacyjny), a następnie po prostu odczytać plik.
[edit: jak to, co zrobił Ray: +1]
To zmusza cię do napisania pliku w miejscu, do którego potrzebujesz pozwolenia, musisz znaleźć lokalizację i nazwę i nie wolno zapomnieć o usunięciu, gdy skończysz. Łatwiejszy sposób użycia 'RedirectStandardOutput'. – peSHIr
można uruchomić dowolny program wiersza poleceń za pomocą klasy procesu i ustawić właściwość StandardOutput instancji proces z czytnikiem strumienia tworzonego (albo na podstawie ciąg lub lokalizacja pamięci). Po zakończeniu procesu możesz zrobić to, co potrzebujesz w tym strumieniu.
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();
}
Oto krótka próbka:
//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();
+1 ładnie i łatwo! Dzięki – Evildonald
istnieje klasa ProcessHelper w PublicDomain otwarty kod źródłowy, które mogą Cię zainteresować.
dowolny pełny kod przykładowy? – Kiquenet
Istnieje jeszcze jeden parametr znalazłem użyteczne, którego używam do wyeliminowania okno procesu
pProcess.StartInfo.CreateNoWindow = true;
to pomaga ukryć czarne okno konsoli z użytkownikiem całkowicie, jeśli to, co chcesz.
Uratowałeś mi dużo bólu głowy. Dzięki. –
Podczas wywoływania "sc" musiałem również ustawić StartInfo.WindowStyle = ProcessWindowStyle.Hidden. – Pedro
// 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) +
"'";
}
Bardzo kompleksowy przykład, dziękuję – ShahidAzim
Może chcieć zmienić OutputDataReceived handler na stdOut.AppendLine() –
Moim zdaniem, jest to o wiele bardziej kompleksowe rozwiązanie niż zaakceptowana odpowiedź. Używam go teraz i nie użyłem zaakceptowanego, ale tego naprawdę brakuje. – ProfK
Może to być przydatne dla kogoś, jeśli próbuje kwerendy lokalnej pamięci podręcznej ARP na PC/Server.
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();
}
Jeśli nie przeszkadza wprowadzenie zależność, CliWrap może uprościć to dla ciebie:
var cli = new Cli("target.exe");
var output = await cli.ExecuteAsync("arguments", "stdin");
var stdout = output.StandardOutput;
Zaakceptowanych odpowiedź na tej stronie ma słabość, który jest kłopotliwy w rzadkich sytuacjach. Istnieją dwa uchwyty plików, które programy piszą według konwencji, stdout i stderr. Po przeczytaniu pojedynczego uchwytu pliku, takiego jak odpowiedź od Ray, a program, który uruchamiasz, zapisuje dostatecznie dużo danych na stderr, zapełni wyjściowy bufor stderr i blok. Wtedy twoje dwa procesy są zablokowane. Rozmiar bufora może wynosić 4K. Jest to niezwykle rzadkie w krótkotrwałych programach, ale jeśli masz długotrwały program, który wielokrotnie wysyła do stderr, to w końcu się to stanie. Jest to trudne do debugowania i śledzenia.
Istnieje kilka dobrych sposobów radzenia sobie z tym.
Jednym ze sposobów jest wykonanie cmd.exe zamiast swojego programu i użyć/c argument cmd.exe powołać swój program wraz z „2> & 1” argumentu do cmd.exe, aby poinformować go połączyć stdout i stderr.
var p = new Process(); p.StartInfo.FileName = "cmd.exe"; p.StartInfo.Arguments = "/c mycmd.exe 2>&1";
Innym sposobem jest użycie modelu programowania, który odczytuje oba uchwyty w tym samym czasie.
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();
Tylko dla zabawy, tu jest mój zakończone rozwiązaniem dla coraz wyjście Pythonie - pod kliknięcia przycisku - z raportowania błędów. Wystarczy dodać przycisk o nazwie "butPython" i etykietę o nazwie "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);
}
}
Zobacz także http://stackoverflow.com/a/5367686/492 - pokazuje zdarzenia wyjściowe i błędy. –