2008-10-15 63 views
397

¿Cómo ejecuto un programa de línea de comandos desde C# y obtengo los resultados STD OUT? Específicamente, quiero ejecutar DIFF en dos archivos que están seleccionados mediante programación y escribir los resultados en un cuadro de texto. Sí, podría resolver esto por mí mismo, pero seguramente alguien ha hecho algo parecido y yo soy un vago ...Cómo: Ejecutar línea de comandos en C#, obtener resultados STD OUT

+2

Ver también http://stackoverflow.com/a/5367686/492 - que muestra los eventos para la salida y los errores. –

Respuesta

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

El código es de MSDN.

+203

Es habitual agregar una atribución cuando corta y pega código para otro lugar. Esto fue tomado de http://msdn.microsoft.com/en-us/library/system.diagnostics.process.standardoutput.aspx –

+5

¿Hay alguna manera de hacerlo sin un archivo por lotes? La cosa es que necesito enviar algunos parámetros al comando. Estoy usando el xsd.exe /tipo: , así que necesito poder establecer el Assembly y el ClassName, y luego ejecutar el comando. – Carlo

+22

Puede agregar argumentos a su llamada a través de la cadena '{YourProcessObject} .StartInfo.Arguments'. – patridge

4

esto puede no ser la mejor/manera más fácil, pero puede ser una opción:

Cuando ejecutas desde tu código, agrega "> salida.txt" y luego lee en el archivo output.txt.

7

Necesitará usar ProcessStartInfo con RedirectStandardOutput habilitado - entonces puede leer el flujo de salida. Es posible que le resulte más fácil utilizar ">" para redirigir la salida a un archivo (a través del sistema operativo), y luego simplemente lea el archivo.

[editar: al igual que lo hizo Ray: 1]

+9

Eso obliga a escribir un archivo en algún lugar para el que necesita permiso, necesita encontrar una ubicación y un nombre y no debe olvidarse de eliminar cuando haya terminado con él. Más fácil de usar 'RedirectStandardOutput' en realidad. – peSHIr

4

Puede iniciar cualquier programa de línea de comandos usando la clase de proceso, y establezca la propiedad StandardOutput de la instancia de proceso con un lector corriente se crea (ya sea basada en una cadena o una ubicación de memoria). Después de que el proceso se complete, puedes hacer lo que necesites en esa transmisión.

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

Aquí hay una muestra rápida:

//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 ¡agradable y fácil! Gracias – Evildonald

2

hay una clase ProcessHelper en PublicDomain código fuente abierto que pueden interesarle.

+0

cualquier código de muestra completo? – Kiquenet

89

Hay otro parámetro que encontraron útiles, que utilizo para eliminar la ventana de proceso

pProcess.StartInfo.CreateNoWindow = true; 

esto ayuda a ocultar la ventana de la consola de usuario completamente negro, si eso es lo que desea.

+1

Me salvó un montón de dolor de cabeza. Gracias. –

+1

Al llamar a "sc" también tuve que configurar 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

Un ejemplo muy completo, Gracias – ShahidAzim

+2

Puede que desee cambiar el manejador OutputDataReceived a stdOut.AppendLine() –

+2

En mi opinión, esta es una solución mucho más completa que la aceptada. Lo estoy usando ahora, y no he usado el aceptado, pero realmente parece que falta. – ProfK

1

Esto podría ser útil para alguien si intenta consultar la memoria caché ARP local en una PC/Servidor.

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

Si no te importa la introducción de una dependencia, CliWrap puede simplificar esto para usted:

var cli = new Cli("target.exe"); 
var output = await cli.ExecuteAsync("arguments", "stdin"); 
var stdout = output.StandardOutput; 
1

La respuesta aceptada en esta página tiene una debilidad que es problemático en situaciones raras. Hay dos manejadores de archivos a los que escriben los programas por convención, stdout y stderr. Si acaba de leer un identificador de archivo único como la respuesta de Ray, y el programa que está iniciando escribe suficiente salida en stderr, llenará el búfer stderr de salida y bloqueará. Entonces tus dos procesos están estancados. El tamaño del buffer puede ser 4K. Esto es extremadamente raro en programas de corta duración, pero si tiene un programa de ejecución prolongada que genera salidas repetidas a stderr, eventualmente ocurrirá. Esto es complicado de depurar y rastrear.

Hay un par de buenas maneras de lidiar con esto.

  1. Una forma es ejecutar cmd.exe en lugar de su programa y utilizar el argumento/c para cmd.exe para invocar el programa junto con el argumento "2> & 1" a cmd.exe para contarlo fusionar stdout y stderr.

     var p = new Process(); 
         p.StartInfo.FileName = "cmd.exe"; 
         p.StartInfo.Arguments = "/c mycmd.exe 2>&1"; 
    
  2. Otra forma es utilizar un modelo de programación que se lee tanto maneja al mismo tiempo.

     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

Sólo por diversión, aquí está mi solución completa para conseguir la salida PYTHON - bajo un clic de botón - con el informe de errores. Sólo tiene que añadir un botón llamado "butPython" y una etiqueta llamada "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); 
      } 
    } 
Cuestiones relacionadas