Ejecutar comandos del símbolo del sistema

605

¿Hay alguna forma de ejecutar comandos del símbolo del sistema desde una aplicación C #? Si es así, ¿cómo haría lo siguiente?

copy /b Image1.jpg + Archive.rar Image2.jpg

Básicamente, esto incrusta un archivo RAR dentro de la imagen JPG. Me preguntaba si había una manera de hacer esto automáticamente en C #.

usuario
fuente
66
Duplicado de stackoverflow.com/questions/181719/… (hay una respuesta que hace lo que quieres).
Matt Hamilton
stackoverflow.com/a/5367686/492 tiene una mejor respuesta
CAD bloke

Respuestas:

918

esto es todo lo que tiene que hacer para ejecutar comandos de shell desde C #

string strCmdText;
strCmdText= "/C copy /b Image1.jpg + Archive.rar Image2.jpg";
System.Diagnostics.Process.Start("CMD.exe",strCmdText);

EDITAR:

Esto es para ocultar la ventana de cmd.

System.Diagnostics.Process process = new System.Diagnostics.Process();
System.Diagnostics.ProcessStartInfo startInfo = new System.Diagnostics.ProcessStartInfo();
startInfo.WindowStyle = System.Diagnostics.ProcessWindowStyle.Hidden;
startInfo.FileName = "cmd.exe";
startInfo.Arguments = "/C copy /b Image1.jpg + Archive.rar Image2.jpg";
process.StartInfo = startInfo;
process.Start();

EDITAR: 2

Importante es que el argumento comienza con lo /Ccontrario no funcionará. Cómo dijo Scott Ferguson : "Ejecuta el comando especificado por la cadena y luego termina".

RameshVel
fuente
166
/ C Ejecuta el comando especificado por cadena y luego termina
Scott Ferguson
16
es sólo para decirle al cmd para ejecutar y terminar (Dont espera para cualquier entrada del usuario para cerrar la ventana)
RameshVel
3
Gracias, una pregunta más. ¿Hay alguna manera de ocultar el símbolo del sistema durante esto?
usuario
99
No veo cómo soy el único que piensa que esta es una idea horrible. Sí, esto funcionará, pero está completamente y totalmente mal. Generar procesos CMD para realizar operaciones simples de E / S es incorrecto, incluso si funciona. Lea la documentación en el espacio de nombres System.IO. Hay una funcionalidad más que suficiente para hacer lo que necesita hacer sin generar procesos innecesarios.
Instancia Hunter
56
FYI: Use process.WaitForExit () para esperar a que el proceso se complete antes de continuar y process.ExitCode para obtener el código de salida del proceso.
shindigo 01 de
122

Intenté la solución @RameshVel pero no pude pasar argumentos en mi aplicación de consola. Si alguien experimenta el mismo problema, aquí hay una solución:

using System.Diagnostics;

Process cmd = new Process();
cmd.StartInfo.FileName = "cmd.exe";
cmd.StartInfo.RedirectStandardInput = true;
cmd.StartInfo.RedirectStandardOutput = true;
cmd.StartInfo.CreateNoWindow = true;
cmd.StartInfo.UseShellExecute = false;
cmd.Start();

cmd.StandardInput.WriteLine("echo Oscar");
cmd.StandardInput.Flush();
cmd.StandardInput.Close();
cmd.WaitForExit();
Console.WriteLine(cmd.StandardOutput.ReadToEnd());
Ogglas
fuente
2
bueno, no le di la oportunidad de pensar que en mi máquina hay algunas restricciones de administrador o antivirus, pero ... ¡el código anterior funciona! gracias Ogglas
Pete Kozak
66
esta línea: cmd.StartInfo.CreateNoWindow = true; Me salvó el día.
Ganesh Kamath - 'Code Frenzy'
¿Hay alguna forma de ejecutar múltiples comandos en un solocmd.StandardInput.WriteLine(@"cd C:\Test; pwd")
Zach Smith
36
var proc1 = new ProcessStartInfo();
string anyCommand; 
proc1.UseShellExecute = true;

proc1.WorkingDirectory = @"C:\Windows\System32";

proc1.FileName = @"C:\Windows\System32\cmd.exe";
proc1.Verb = "runas";
proc1.Arguments = "/c "+anyCommand;
proc1.WindowStyle = ProcessWindowStyle.Hidden;
Process.Start(proc1);
HackerMan
fuente
2
¿Cuál es el @signo en C #?
Pacerier
66
@Pacerier Le dice al compilador que escape de todos los caracteres que normalmente tendrían que escapar en la cadena, en este caso \. Entonces, sin la \, su código se vería asíproc1.FileName = "C:\\Windows\\System32\\cmd.exe";
James Ko
1
Cabe señalar que proc1.Verb = "runas";hace que este proceso se ejecute con privilegios elevados ... Esto no siempre está previsto.
Dinei
1
¿Cómo puedo hacer que esta ventana de cmd no se cierre después de que haya terminado?
Hrvoje T
1
Descubrí que llamar a 'ruta de CD' unida por '&&' con otros comandos en la línea siempre se ejecuta en último lugar, incluso si fue primero. su: 'proc1.WorkingDirectory = @ "C: \ Windows \ System32";' fue muy útil! ¡Gracias!
Nozim Turakulov
11

Ninguna de las respuestas anteriores ayudó por alguna razón, parece que barren los errores debajo de la alfombra y dificultan la resolución de los comandos. Así que terminé con algo como esto, tal vez ayude a alguien más:

var proc = new Process
{
    StartInfo = new ProcessStartInfo
    {
        FileName = @"C:\Program Files\Microsoft Visual Studio 14.0\Common7\IDE\tf.exe",
        Arguments = "checkout AndroidManifest.xml",
        UseShellExecute = false,
        RedirectStandardOutput = true,
        CreateNoWindow = true,
        WorkingDirectory = @"C:\MyAndroidApp\"
    }
};

proc.Start();
Matt Bonness
fuente
Si quisiera compilar esto en una aplicación de consola independiente, ¿qué otro código tendría que agregarse para que funcione? (Soy un novato en todas estas cosas de programación, solo hice algunas secuencias de comandos). Estoy usando csc.exe por cierto.
script'n'code
@copyitright Un espacio de nombres y clase. Si solo crea un nuevo proyecto, se generarán para usted.
coinbird
Ah no importa. Si usa la cmd.exeaplicación, puede pasar comandos como argumentos.
Zach Smith
Para la posteridad: quería que el proceso se ejecutara echo Hello World!y mostrara la salida del comando en la ventana cmd que aparece. Así que he intentado: Filename = @"echo", Arguments = "Hello World!", UseShellExecute = false, RedirectStandardOuput = false, CreateNoWindow = false. Esto permitió que la ventana cmd de la aplicación principal mostrara "¡Hola mundo!" (lo cual tiene sentido porque stdout no se redirigió al proceso secundario).
Minh Tran
10

Aunque técnicamente esto no responde directamente a la pregunta planteada, sí responde a la pregunta de cómo hacer lo que el cartel original quería hacer: combinar archivos. En todo caso, esta es una publicación para ayudar a los novatos a comprender de qué están hablando Instance Hunter y Konstantin.

Este es el método que uso para combinar archivos (en este caso, un jpg y un zip). Tenga en cuenta que creo un búfer que se llena con el contenido del archivo zip (en pequeños fragmentos en lugar de en una operación de lectura grande), y luego el búfer se escribe en la parte posterior del archivo jpg hasta el final del archivo zip alcanzado:

private void CombineFiles(string jpgFileName, string zipFileName)
{
    using (Stream original = new FileStream(jpgFileName, FileMode.Append))
    {
        using (Stream extra = new FileStream(zipFileName, FileMode.Open, FileAccess.Read))
        {
            var buffer = new byte[32 * 1024];

            int blockSize;
            while ((blockSize = extra.Read(buffer, 0, buffer.Length)) > 0)
            {
                original.Write(buffer, 0, blockSize);
            }
        }
    }
}
CarllDev
fuente
9

si desea mantener abierta la ventana de cmd o desea usarla en winform / wpf, úsela así

    string strCmdText;
//For Testing
    strCmdText= "/K ipconfig";

 System.Diagnostics.Process.Start("CMD.exe",strCmdText);

/ K

Mantendrá la ventana cmd abierta

Diseño unico
fuente
Agradable. Encontré esta documentación para el cmdcomando y sus parámetros.
pius
8

Sí, la hay (ver enlace en el comentario de Matt Hamilton), pero sería más fácil y mejor usar las clases IO de .NET. Puede usar File.ReadAllBytes para leer los archivos y luego File.WriteAllBytes para escribir la versión "incrustada".

Cazador de instancias
fuente
11
Cargar archivos completos en la memoria solo para agregarlos entre sí no es muy eficiente, especialmente si los archivos son lo suficientemente grandes.
Konstantin Spirin
77
Intenta mirar el espíritu de la respuesta. El punto es que .NET tiene más que suficientes clases y funciones de E / S para hacer esto sin tener que llamar al shell del sistema operativo. Las funciones particulares que mencioné pueden no ser las mejores, pero esas fueron solo las más simples. No tiene ningún sentido llamar al shell para hacer esto.
Instancia Hunter
7

Puede hacer esto usando CliWrap en una línea:

var stdout = new Cli("cmd")
         .Execute("copy /b Image1.jpg + Archive.rar Image2.jpg")
         .StandardOutput;
Tyrrrz
fuente
Voté esto ... pero parece que falta el repositorio ahora:Unable to find package 'CliWrap' at source
Zach Smith
1
@ZachSmith no está seguro de lo que quieres decir, nuget.org/packages/CliWrap parece funcionar bien. El enlace original también.
Tyrrrz
Ah, lo siento ... por alguna razón, cuando no pude conectarme a mi nuget repo a través de vpn, no pude instalar este paquete. Nuget sigue siendo un misterio para mí. debe haberlo configurado mal
Zach Smith
6

con una referencia a Microsoft.VisualBasic

Interaction.Shell("copy /b Image1.jpg + Archive.rar Image2.jpg", AppWinStyle.Hide);
Slai
fuente
5

Aquí hay una pequeña versión simple y menos código. También ocultará la ventana de la consola.

System.Diagnostics.Process process = new System.Diagnostics.Process();
process.StartInfo.WindowStyle = System.Diagnostics.ProcessWindowStyle.Hidden;
process.StartInfo.FileName = "cmd.exe";
process.StartInfo.Arguments = "/C copy /b Image1.jpg + Archive.rar Image2.jpg";
process.Start();
kamalpreet
fuente
5

si desea ejecutar el comando en modo asíncrono e imprimir los resultados. puedes esta clase:

    public static class ExecuteCmd
{
    /// <summary>
    /// Executes a shell command synchronously.
    /// </summary>
    /// <param name="command">string command</param>
    /// <returns>string, as output of the command.</returns>
    public static void ExecuteCommandSync(object command)
    {
        try
        {
            // create the ProcessStartInfo using "cmd" as the program to be run, and "/c " as the parameters.
            // Incidentally, /c tells cmd that we want it to execute the command that follows, and then exit.
            System.Diagnostics.ProcessStartInfo procStartInfo = new System.Diagnostics.ProcessStartInfo("cmd", "/c " + command);
            // The following commands are needed to redirect the standard output. 
            //This means that it will be redirected to the Process.StandardOutput StreamReader.
            procStartInfo.RedirectStandardOutput =  true;
            procStartInfo.UseShellExecute = false;
            // Do not create the black window.
            procStartInfo.CreateNoWindow = true;
            // Now we create a process, assign its ProcessStartInfo and start it
            System.Diagnostics.Process proc = new System.Diagnostics.Process();
            proc.StartInfo = procStartInfo;
            proc.Start();

            // Get the output into a string
            string result = proc.StandardOutput.ReadToEnd();

            // Display the command output.
            Console.WriteLine(result);
        }
        catch (Exception objException)
        {
            // Log the exception
            Console.WriteLine("ExecuteCommandSync failed" + objException.Message);
        }
    }

    /// <summary>
    /// Execute the command Asynchronously.
    /// </summary>
    /// <param name="command">string command.</param>
    public static void ExecuteCommandAsync(string command)
    {
        try
        {
            //Asynchronously start the Thread to process the Execute command request.
            Thread objThread = new Thread(new ParameterizedThreadStart(ExecuteCommandSync));
            //Make the thread as background thread.
            objThread.IsBackground = true;
            //Set the Priority of the thread.
            objThread.Priority = ThreadPriority.AboveNormal;
            //Start the thread.
            objThread.Start(command);
        }
        catch (ThreadStartException )
        {
            // Log the exception
        }
        catch (ThreadAbortException )
        {
            // Log the exception
        }
        catch (Exception )
        {
            // Log the exception
        }
    }

}
Elad
fuente
2

Puede lograr esto utilizando el siguiente método (como se menciona en otras respuestas):

strCmdText = "'/C some command";
Process.Start("CMD.exe", strCmdText);

Cuando probé los métodos enumerados anteriormente, descubrí que mi comando personalizado no funcionaba con la sintaxis de algunas de las respuestas anteriores.

Descubrí que los comandos más complejos deben encapsularse entre comillas para funcionar:

string strCmdText;
strCmdText = "'/C cd " + path + " && composer update && composer install -o'";
Process.Start("CMD.exe", strCmdText);
Vladimir verleg
fuente
1

puede usar simplemente escribir el código en una .batextensión de formato, el código del archivo por lotes:

c:/ copy /b Image1.jpg + Archive.rar Image2.jpg

usa este código c #:

Process.Start("file_name.bat")

XMMR12
fuente
si desea ocultar el cmd mientras se ejecuta, puede usar un código de secuencia de comandos básico visual simple en una .vbsextensión de formato, el código:CreateObject("Wscript.Shell").Run "filename.bat",0,True
XMMR12