2008-10-15 4 views
397

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

+2

Zobacz także http://stackoverflow.com/a/5367686/492 - pokazuje zdarzenia wyjściowe i błędy. –

Odpowiedz

448
// 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.

+203

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 –

+5

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 /type: , więc muszę mieć możliwość ustawienia zarówno Assembly, jak i ClassName, a następnie uruchomić polecenie. – Carlo

+22

Możesz dodać argumenty do swojego połączenia za pomocą łańcucha '{YourProcessObject} .StartInfo.Arguments'. – patridge

4

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.

7

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]

+9

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

4

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.

13
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(); 
} 
119

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(); 
+2

+1 ładnie i łatwo! Dzięki – Evildonald

2

istnieje klasa ProcessHelper w PublicDomain otwarty kod źródłowy, które mogą Cię zainteresować.

+0

dowolny pełny kod przykładowy? – Kiquenet

89

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.

+1

Uratowałeś mi dużo bólu głowy. Dzięki. –

+1

Podczas wywoływania "sc" musiałem również ustawić StartInfo.WindowStyle = ProcessWindowStyle.Hidden. – Pedro

70
// 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) + 
     "'"; 
} 
+2

Bardzo kompleksowy przykład, dziękuję – ShahidAzim

+2

Może chcieć zmienić OutputDataReceived handler na stdOut.AppendLine() –

+2

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

1

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(); 
     } 
2

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; 
1

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.

  1. 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"; 
    
  2. 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(); 
    
0

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); 
      } 
    }