Można to dość łatwo osiągnąć za pomocą właściwości ProcessStartInfo.RedirectStandardOutput . Pełny przykład znajduje się w połączonej dokumentacji MSDN; jedynym zastrzeżeniem jest to, że może być konieczne przekierowanie standardowego strumienia błędów, aby zobaczyć wszystkie dane wyjściowe aplikacji.
Jeśli nie chcesz dodatkowej nowej linii na końcu, po prostu użyj Console.Writezamiast tego.
tm1
3
Należy zauważyć, że jeśli używasz ReadToEnd () w połączeniu z aplikacją konsolową, która ma możliwość monitowania użytkownika o wprowadzenie danych. Np .: Zastąp plik: T czy N? etc Następnie ReadToEnd może spowodować wyciek pamięci, ponieważ proces nigdy nie kończy się podczas oczekiwania na dane wejściowe użytkownika. Bezpieczniejszym sposobem przechwytywania danych wyjściowych jest użycie procedury obsługi zdarzeń process.OutputDataReceived i umożliwienie procesowi powiadamiania aplikacji o otrzymanych wynikach.
Baaleos
Jak przechwytywać, jeśli kod jest wdrażany w aplikacji Azure Webapp, ponieważ compiler.StartInfo.FileName = "csc.exe"; może nie istnieć!
Asif Iqbal
Jak przechwytywać, jeśli kod jest wdrażany w aplikacji Azure Webapp, ponieważ compiler.StartInfo.FileName = "csc.exe"; może nie istnieć!
Asif Iqbal
42
Jest to nieco lepsze od akceptowanej odpowiedzi z @mdb . W szczególności przechwytujemy również wyjście błędów procesu. Ponadto przechwytujemy te dane wyjściowe za pośrednictwem zdarzeń, ponieważ ReadToEnd()nie działa, jeśli chcesz przechwytywać zarówno błędy, jak i zwykłe dane wyjściowe. Zajęło mi trochę czasu, aby to zadziałało, ponieważ w rzeczywistości wymaga to również BeginxxxReadLine()połączeń po Start().
Sposób asynchroniczny:
using System.Diagnostics;
Process process = new Process();
voidLaunchProcess()
{
process.EnableRaisingEvents = true;
process.OutputDataReceived += new System.Diagnostics.DataReceivedEventHandler(process_OutputDataReceived);
process.ErrorDataReceived += new System.Diagnostics.DataReceivedEventHandler(process_ErrorDataReceived);
process.Exited += new System.EventHandler(process_Exited);
process.StartInfo.FileName = "some.exe";
process.StartInfo.Arguments = "param1 param2";
process.StartInfo.UseShellExecute = false;
process.StartInfo.RedirectStandardError = true;
process.StartInfo.RedirectStandardOutput = true;
process.Start();
process.BeginErrorReadLine();
process.BeginOutputReadLine();
//below line is optional if we want a blocking call//process.WaitForExit();
}
voidprocess_Exited(object sender, EventArgs e)
{
Console.WriteLine(string.Format("process exited with code {0}\n", process.ExitCode.ToString()));
}
voidprocess_ErrorDataReceived(object sender, DataReceivedEventArgs e)
{
Console.WriteLine(e.Data + "\n");
}
voidprocess_OutputDataReceived(object sender, DataReceivedEventArgs e)
{
Console.WriteLine(e.Data + "\n");
}
Otrzymasz honorowe miejsce na liście podziękowań mojej aplikacji.
marsh-wiggle
to jest łatwy do zrozumienia, piękny kod. Moim jedynym chwytakiem jest to, że niepotrzebnie dodajesz nowe linie. "Writeline" dodaje jeden za ciebie, więc efektem netto jest to, że przechwycone dane wyjściowe mają pustą linię wstawioną co drugą linię.
ConsoleAppLauncher to biblioteka open source stworzona specjalnie po to, aby odpowiedzieć na to pytanie. Przechwytuje wszystkie dane wyjściowe generowane w konsoli i zapewnia prosty interfejs do uruchamiania i zamykania aplikacji konsoli.
Zdarzenie ConsoleOutput jest wywoływane za każdym razem, gdy konsola zapisuje nowy wiersz na wyjście standardowe / błąd. Wiersze są umieszczane w kolejce i na pewno będą zgodne z kolejnością wyjściową.
Przykładowe wywołanie, aby uzyskać pełne dane wyjściowe konsoli:
// Run simplest shell command and return its output.publicstaticstringGetWindowsVersion()
{
return ConsoleApp.Run("cmd", "/c ver").Output.Trim();
}
Próbka z opiniami na żywo:
// Run ping.exe asynchronously and return roundtrip times back to the caller in a callbackpublicstaticvoidPingUrl(string url, Action<string> replyHandler)
{
var regex = new Regex("(time=|Average = )(?<time>.*?ms)", RegexOptions.Compiled);
var app = new ConsoleApp("ping", url);
app.ConsoleOutput += (o, args) =>
{
var match = regex.Match(args.Line);
if (match.Success)
{
var roundtripTime = match.Groups["time"].Value;
replyHandler(roundtripTime);
}
};
app.Run();
}
Przydatne może być również API, które umożliwia przeglądanie wyników konsolowych bieżącego procesu (w istniejącej kontrolce lub oknie podręcznym). Zobacz ten post na blogu, aby uzyskać więcej informacji: http://o2platform.wordpress.com/2011/11/26/api_consoleout-cs-inprocess-capture-of-the-console-output/ (ten blog zawiera również szczegółowe informacje o tym, jak konsumować konsolowe dane wyjściowe nowych procesów)
Zrobiłem wersję reaktywną, która akceptuje wywołania zwrotne dla stdOut i StdErr. onStdOuti onStdErrsą wywoływane asynchronicznie,
gdy tylko nadejdą dane (przed zakończeniem procesu).
publicstatic Int32 RunProcess(String path,
String args,
Action<String> onStdOut = null,
Action<String> onStdErr = null)
{
var readStdOut = onStdOut != null;
var readStdErr = onStdErr != null;
var process = new Process
{
StartInfo =
{
FileName = path,
Arguments = args,
CreateNoWindow = true,
UseShellExecute = false,
RedirectStandardOutput = readStdOut,
RedirectStandardError = readStdErr,
}
};
process.Start();
if (readStdOut) Task.Run(() => ReadStream(process.StandardOutput, onStdOut));
if (readStdErr) Task.Run(() => ReadStream(process.StandardError, onStdErr));
process.WaitForExit();
return process.ExitCode;
}
privatestaticvoidReadStream(TextReader textReader, Action<String> callback)
{
while (true)
{
var line = textReader.ReadLine();
if (line == null)
break;
callback(line);
}
}
Przykładowe użycie
Następujące będzie działać executablez argsi drukować
stdOut w kolorze białym
stdErr na czerwono
do konsoli.
RunProcess(
executable,
args,
s => { Console.ForegroundColor = ConsoleColor.White; Console.WriteLine(s); },
s => { Console.ForegroundColor = ConsoleColor.Red; Console.WriteLine(s); }
);
Process p = new Process(); // Create new object
p.StartInfo.UseShellExecute = false; // Do not use shell
p.StartInfo.RedirectStandardOutput = true; // Redirect output
p.StartInfo.FileName = "c:\\python26\\python.exe"; // Path of our Python compiler
p.StartInfo.Arguments = "c:\\python26\\Hello_C_Python.py"; // Path of the .py to be executed
Kiedy StandardOutput.ReadToEnd()go użyjesz , nie wróci do następnej instrukcji aż do końca aplikacji. więc Twój limit czasu w WaitForExit (timeoutMilliseconds) nie działa! (Twój kod się zawiesi!)
Odpowiedzi:
Można to dość łatwo osiągnąć za pomocą właściwości ProcessStartInfo.RedirectStandardOutput . Pełny przykład znajduje się w połączonej dokumentacji MSDN; jedynym zastrzeżeniem jest to, że może być konieczne przekierowanie standardowego strumienia błędów, aby zobaczyć wszystkie dane wyjściowe aplikacji.
Process compiler = new Process(); compiler.StartInfo.FileName = "csc.exe"; compiler.StartInfo.Arguments = "/r:System.dll /out:sample.exe stdstr.cs"; compiler.StartInfo.UseShellExecute = false; compiler.StartInfo.RedirectStandardOutput = true; compiler.Start(); Console.WriteLine(compiler.StandardOutput.ReadToEnd()); compiler.WaitForExit();
źródło
Console.Write
zamiast tego.Jest to nieco lepsze od akceptowanej odpowiedzi z @mdb . W szczególności przechwytujemy również wyjście błędów procesu. Ponadto przechwytujemy te dane wyjściowe za pośrednictwem zdarzeń, ponieważ
ReadToEnd()
nie działa, jeśli chcesz przechwytywać zarówno błędy, jak i zwykłe dane wyjściowe. Zajęło mi trochę czasu, aby to zadziałało, ponieważ w rzeczywistości wymaga to równieżBeginxxxReadLine()
połączeń poStart()
.Sposób asynchroniczny:
using System.Diagnostics; Process process = new Process(); void LaunchProcess() { process.EnableRaisingEvents = true; process.OutputDataReceived += new System.Diagnostics.DataReceivedEventHandler(process_OutputDataReceived); process.ErrorDataReceived += new System.Diagnostics.DataReceivedEventHandler(process_ErrorDataReceived); process.Exited += new System.EventHandler(process_Exited); process.StartInfo.FileName = "some.exe"; process.StartInfo.Arguments = "param1 param2"; process.StartInfo.UseShellExecute = false; process.StartInfo.RedirectStandardError = true; process.StartInfo.RedirectStandardOutput = true; process.Start(); process.BeginErrorReadLine(); process.BeginOutputReadLine(); //below line is optional if we want a blocking call //process.WaitForExit(); } void process_Exited(object sender, EventArgs e) { Console.WriteLine(string.Format("process exited with code {0}\n", process.ExitCode.ToString())); } void process_ErrorDataReceived(object sender, DataReceivedEventArgs e) { Console.WriteLine(e.Data + "\n"); } void process_OutputDataReceived(object sender, DataReceivedEventArgs e) { Console.WriteLine(e.Data + "\n"); }
źródło
Użyj ProcessInfo.RedirectStandardOutput, aby przekierować dane wyjściowe podczas tworzenia procesu konsoli.
Następnie możesz użyć Process.StandardOutput do odczytania danych wyjściowych programu.
Drugi link zawiera przykładowy kod, jak to zrobić.
źródło
ConsoleAppLauncher to biblioteka open source stworzona specjalnie po to, aby odpowiedzieć na to pytanie. Przechwytuje wszystkie dane wyjściowe generowane w konsoli i zapewnia prosty interfejs do uruchamiania i zamykania aplikacji konsoli.
Zdarzenie ConsoleOutput jest wywoływane za każdym razem, gdy konsola zapisuje nowy wiersz na wyjście standardowe / błąd. Wiersze są umieszczane w kolejce i na pewno będą zgodne z kolejnością wyjściową.
Dostępne również jako pakiet NuGet .
Przykładowe wywołanie, aby uzyskać pełne dane wyjściowe konsoli:
// Run simplest shell command and return its output. public static string GetWindowsVersion() { return ConsoleApp.Run("cmd", "/c ver").Output.Trim(); }
Próbka z opiniami na żywo:
// Run ping.exe asynchronously and return roundtrip times back to the caller in a callback public static void PingUrl(string url, Action<string> replyHandler) { var regex = new Regex("(time=|Average = )(?<time>.*?ms)", RegexOptions.Compiled); var app = new ConsoleApp("ping", url); app.ConsoleOutput += (o, args) => { var match = regex.Match(args.Line); if (match.Success) { var roundtripTime = match.Groups["time"].Value; replyHandler(roundtripTime); } }; app.Run(); }
źródło
Dodałem kilka metod pomocniczych do Platformy O2 (projekt Open Source), które pozwalają łatwo skryptować interakcję z innym procesem poprzez wyjście i wejście konsoli (patrz http://code.google.com/p/o2platform/ źródło / przeglądanie / trunk / O2_Scripts / APIs / Windows / CmdExe / CmdExeAPI.cs )
Przydatne może być również API, które umożliwia przeglądanie wyników konsolowych bieżącego procesu (w istniejącej kontrolce lub oknie podręcznym). Zobacz ten post na blogu, aby uzyskać więcej informacji: http://o2platform.wordpress.com/2011/11/26/api_consoleout-cs-inprocess-capture-of-the-console-output/ (ten blog zawiera również szczegółowe informacje o tym, jak konsumować konsolowe dane wyjściowe nowych procesów)
źródło
Zrobiłem wersję reaktywną, która akceptuje wywołania zwrotne dla stdOut i StdErr.
onStdOut
ionStdErr
są wywoływane asynchronicznie,gdy tylko nadejdą dane (przed zakończeniem procesu).
public static Int32 RunProcess(String path, String args, Action<String> onStdOut = null, Action<String> onStdErr = null) { var readStdOut = onStdOut != null; var readStdErr = onStdErr != null; var process = new Process { StartInfo = { FileName = path, Arguments = args, CreateNoWindow = true, UseShellExecute = false, RedirectStandardOutput = readStdOut, RedirectStandardError = readStdErr, } }; process.Start(); if (readStdOut) Task.Run(() => ReadStream(process.StandardOutput, onStdOut)); if (readStdErr) Task.Run(() => ReadStream(process.StandardError, onStdErr)); process.WaitForExit(); return process.ExitCode; } private static void ReadStream(TextReader textReader, Action<String> callback) { while (true) { var line = textReader.ReadLine(); if (line == null) break; callback(line); } }
Przykładowe użycie
Następujące będzie działać
executable
zargs
i drukowaćdo konsoli.
źródło
Z PythonTR - Python Programcıları Derneği, e-kitap, örnek :
Process p = new Process(); // Create new object p.StartInfo.UseShellExecute = false; // Do not use shell p.StartInfo.RedirectStandardOutput = true; // Redirect output p.StartInfo.FileName = "c:\\python26\\python.exe"; // Path of our Python compiler p.StartInfo.Arguments = "c:\\python26\\Hello_C_Python.py"; // Path of the .py to be executed
źródło
Dodano
process.StartInfo.**CreateNoWindow** = true;
itimeout
.private static void CaptureConsoleAppOutput(string exeName, string arguments, int timeoutMilliseconds, out int exitCode, out string output) { using (Process process = new Process()) { process.StartInfo.FileName = exeName; process.StartInfo.Arguments = arguments; process.StartInfo.UseShellExecute = false; process.StartInfo.RedirectStandardOutput = true; process.StartInfo.CreateNoWindow = true; process.Start(); output = process.StandardOutput.ReadToEnd(); bool exited = process.WaitForExit(timeoutMilliseconds); if (exited) { exitCode = process.ExitCode; } else { exitCode = -1; } } }
źródło
StandardOutput.ReadToEnd()
go użyjesz , nie wróci do następnej instrukcji aż do końca aplikacji. więc Twój limit czasu w WaitForExit (timeoutMilliseconds) nie działa! (Twój kod się zawiesi!)