Выполнить команды командной строки

Есть ли способ запустить команды командной строки из приложения C#? Если так, как бы я сделал следующее:

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

Это в основном встраивает файл RAR в изображение JPG. Мне просто интересно, есть ли способ сделать это автоматически в C#.

18 ответов

Решение

Это все, что вам нужно сделать, запустить команды оболочки из C#

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

РЕДАКТИРОВАТЬ:

Это чтобы скрыть окно 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();

РЕДАКТИРОВАТЬ: 2

Важно то, что аргумент начинается с /C иначе это не сработает. Как сказал Scott Ferguson: "Выполняет команду, указанную в строке, а затем завершается".

Пробовал решение @RameshVel, но я не мог передать аргументы в моем консольном приложении. Если кто-то испытывает ту же проблему, вот решение:

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

По какой-то причине ни один из приведенных выше ответов не помог, похоже, что они скрывают ошибки под ковриком и затрудняют поиск неисправностей в команде. Так что я закончил тем, что пошел с чем-то вроде этого, возможно, это поможет кому-то еще

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

Хотя технически это не дает прямого ответа на поставленный вопрос, оно отвечает на вопрос о том, как сделать то, что хотел сделать первоначальный плакат: объединить файлы. Во всяком случае, этот пост поможет новичкам понять, о чем говорят Инстанс Хантер и Константин.

Этот метод я использую для объединения файлов (в данном случае это jpg и zip). Обратите внимание, что я создаю буфер, который заполняется содержимым zip-файла (небольшими порциями, а не одной большой операцией чтения), а затем буфер записывается в конец jpg-файла до тех пор, пока конец zip-файла не станет достиг:

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

Если вы хотите оставить окно cmd открытым или хотите использовать его в winform/wpf, используйте его следующим образом

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

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

/K

Будет держать окно cmd открытым

Вы можете сделать это, используя CliWrap в одну строку:

var stdout = new Cli("cmd")
         .Execute("copy /b Image1.jpg + Archive.rar Image2.jpg")
         .StandardOutput;

Если вы хотите запустить команду в асинхронном режиме - и распечатать результаты. вы можете вам этот класс:

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

}

Это также можно сделать с помощью P/ Вызов стандартной библиотеки C system функция.

using System.Runtime.InteropServices;

[DllImport("msvcrt.dll")]
public static extern int system(string format);

system("copy Test.txt Test2.txt");

Выход:

      1 file(s) copied.

Со ссылкой на Microsoft.VisualBasic

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

Да, есть (см. Ссылку в комментарии Мэтта Гамильтона), но было бы проще и лучше использовать классы ввода-вывода.NET. Вы можете использовать File.ReadAllBytes для чтения файлов, а затем File.WriteAllBytes для записи "встроенной" версии.

Вот немного простой и менее кодовой версии. Это также скроет окно консоли.

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

У меня есть следующий метод, который я использую для запуска команд командной строки из C#

В первом параметре передайте команду, которую хотите запустить.

      public static string RunCommand(string arguments, bool readOutput)
{
    var output = string.Empty;
    try
    {
        var startInfo = new ProcessStartInfo
        {
            Verb = "runas",
            FileName = "cmd.exe",
            Arguments = "/C "+arguments,
            WindowStyle = ProcessWindowStyle.Hidden,
            UseShellExecute = false,
            CreateNoWindow = true,
            RedirectStandardOutput = true,
            RedirectStandardError = false
        };

        var proc = Process.Start(startInfo);

        if (readOutput)
        {
            output = proc.StandardOutput.ReadToEnd(); 
        }

        proc.WaitForExit(60000);

        return output;
    }
    catch (Exception)
    {
        return output;
    }
}

Вы можете достичь этого, используя следующий метод (как упоминалось в других ответах):

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

Когда я попробовал методы, перечисленные выше, я обнаружил, что моя пользовательская команда не работает с использованием синтаксиса некоторых из ответов выше.

Я обнаружил, что более сложные команды должны быть заключены в кавычки для работы:

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

Вы можете использовать просто написать код в .bat расширение формата, код командного файла:

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

используйте этот код C#:

Process.Start("file_name.bat")

Ты можешь использовать RunProcessAsTask pacakge и запустите процесс асинхронно и легко вот так:

      var processResults = await ProcessEx.RunAsync("git.exe", "pull");
//get proccess result
foreach (var output in processResults.StandardOutput)
{
   Console.WriteLine("Output line: " + output);
}

Это может быть немного прочитано, так что заранее извините. И это мой проверенный и проверенный способ сделать это, может быть более простой способ, но это от меня, когда я бросаю код в стену и смотрю, что застряло

Если это можно сделать с помощью командного файла, то, возможно, более сложная работа - заставить С # написать файл .bat и запустить его. Если вам нужен пользовательский ввод, вы можете поместить его в переменную, а С # записать его в файл. для этого потребуется метод проб и ошибок, потому что это все равно, что управлять марионеткой с помощью другой марионетки.

вот пример. В этом случае функция предназначена для кнопки в приложении форума Windows, которая очищает очередь печати.

      using System.IO;
using System;

   public static void ClearPrintQueue()
    {

        //this is the path the document or in our case batch file will be placed
        string docPath =
         Environment.GetFolderPath(Environment.SpecialFolder.MyDocuments);
        //this is the path process.start usues
        string path1 = docPath + "\\Test.bat";

        // these are the batch commands
        // remember its "", the comma separates the lines
        string[] lines =
        {
            "@echo off",
            "net stop spooler",
            "del %systemroot%\\System32\\spool\\Printers\\* /Q",
            "net start spooler",
            //this deletes the file
            "del \"%~f0\"" //do not put a comma on the last line
        };

        //this writes the string to the file
        using (StreamWriter outputFile = new StreamWriter(Path.Combine(docPath, "test.bat")))
        {
            //This writes the file line by line
            foreach (string line in lines)
                outputFile.WriteLine(line);
        }
        System.Diagnostics.Process.Start(path1);

    }

ЕСЛИ вам нужен ввод пользователя, вы можете попробовать что-то вроде этого.

Это сделано для того, чтобы установить статический IP-адрес компьютера, но спросить пользователя, какой IP, шлюз и DNS-сервер.

вам понадобится это для работы

      public static void SetIPStatic()
    {
//These open pop up boxes which ask for user input
        string STATIC = Microsoft.VisualBasic.Interaction.InputBox("Whats the static IP?", "", "", 100, 100);
        string SUBNET = Microsoft.VisualBasic.Interaction.InputBox("Whats the Subnet?(Press enter for default)", "255.255.255.0", "", 100, 100);
        string DEFAULTGATEWAY = Microsoft.VisualBasic.Interaction.InputBox("Whats the Default gateway?", "", "", 100, 100);
        string DNS = Microsoft.VisualBasic.Interaction.InputBox("Whats the DNS server IP?(Input required, 8.8.4.4 has already been set as secondary)", "", "", 100, 100);



        //this is the path the document or in our case batch file will be placed
        string docPath =
         Environment.GetFolderPath(Environment.SpecialFolder.MyDocuments);
        //this is the path process.start usues
        string path1 = docPath + "\\Test.bat";

        // these are the batch commands
        // remember its "", the comma separates the lines
        string[] lines =
        {
            "SETLOCAL EnableDelayedExpansion",
            "SET adapterName=",
            "FOR /F \"tokens=* delims=:\" %%a IN ('IPCONFIG ^| FIND /I \"ETHERNET ADAPTER\"') DO (",
            "SET adapterName=%%a",
            "REM Removes \"Ethernet adapter\" from the front of the adapter name",
            "SET adapterName=!adapterName:~17!",
            "REM Removes the colon from the end of the adapter name",
            "SET adapterName=!adapterName:~0,-1!",
//the variables that were set before are used here
            "netsh interface ipv4 set address name=\"!adapterName!\" static " + STATIC + " " + STATIC + " " + DEFAULTGATEWAY,
            "netsh interface ipv4 set dns name=\"!adapterName!\" static " + DNS + " primary",
            "netsh interface ipv4 add dns name=\"!adapterName!\" 8.8.4.4 index=2",
            ")",
            "ipconfig /flushdns",
            "ipconfig /registerdns",
            ":EOF",
            "DEL \"%~f0\"",
            ""
        };

        //this writes the string to the file
        using (StreamWriter outputFile = new StreamWriter(Path.Combine(docPath, "test.bat")))
        {
            //This writes the file line by line
            foreach (string line in lines)
                outputFile.WriteLine(line);
        }
        System.Diagnostics.Process.Start(path1);

    }

Как я и сказал. Это может быть немного сложно, но никогда не выходит из строя, если я не напишу пакетные команды неправильно.

Нижеприведенная рабочая программа возвращает версию с использованием нескольких вышеуказанных решений.

      internal class Program
{
    static void Main(string[] args)
    {
        Console.WriteLine(getDotnetversion());
        Console.ReadKey();
    }

    private static string getDotnetversion()
    {
        string version =string.Empty;
        try
        {
            Process cmdDotnet = new Process();
            cmdDotnet.StartInfo.FileName = "dotnet.exe";
            cmdDotnet.StartInfo.RedirectStandardInput = true;
            cmdDotnet.StartInfo.RedirectStandardOutput = true;
            cmdDotnet.StartInfo.CreateNoWindow = true;
            cmdDotnet.StartInfo.UseShellExecute = false;
            cmdDotnet.StartInfo.Arguments = "--version";
            cmdDotnet.Start();
            cmdDotnet.StandardInput.WriteLine("cmd started");
            cmdDotnet.StandardInput.Flush();
            cmdDotnet.StandardInput.Close();
            cmdDotnet.WaitForExit();
            version = cmdDotnet.StandardOutput.ReadToEnd();
        }
        catch
        {
            version = "";
        }
        return version;
    }
}
Другие вопросы по тегам