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

606

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

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

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

пользователь
источник
6
Дубликат stackoverflow.com/questions/181719/… (там есть ответ, который делает то, что вы хотите).
Мэтт Гамильтон
stackoverflow.com/a/5367686/492 имеет лучший ответ
САПР bloke

Ответы:

919

это все, что вам нужно сделать, запустить команды оболочки из 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иначе он не будет работать. Как сказал Скотт Фергюсон : «Выполняет команду, указанную в строке, а затем завершается».

RameshVel
источник
166
/ C Выполняет команду, указанную в строке, а затем завершается
Скотт Фергюсон
16
просто сказать cmd запускаться и завершаться (не ждите, пока пользователь не
введет
3
Спасибо, еще один вопрос. Есть ли способ скрыть командную строку во время этого?
Пользователь
9
Я не понимаю, как я единственный, кто думает, что это ужасная идея. Да, это будет работать, но это совершенно неправильно. Создание процессов CMD для выполнения простых операций ввода-вывода - это неправильно, даже если это работает. Прочитайте документацию по пространству имен System.IO. Там более чем достаточно функциональности, чтобы делать то, что вам нужно, без порождения ненужных процессов.
Охотник за экземплярами
56
К сведению: используйте process.WaitForExit (), чтобы дождаться завершения процесса, прежде чем продолжить, и process.ExitCode, чтобы получить код завершения процесса.
Shindigo
122

Пробовал решение @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());
Ogglas
источник
2
ну, я не дал ему ни малейшего шанса думать, что на моей машине есть некоторые ограничения администратора или антивируса, но .. приведенный выше код работает! спасибо Огглас
Пит Козак
6
эта строка: cmd.StartInfo.CreateNoWindow = true; спас мой день
Ганеш Камат - «Безумный кодекс»
Есть ли способ выполнить несколько команд в однойcmd.StandardInput.WriteLine(@"cd C:\Test; pwd")
Зак Смит
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
источник
2
Что за @знак в C #?
Pacerier
6
@Pacerier Указывает компилятору экранировать все символы, которые обычно должны быть экранированы в строке, в данном случае \. Таким образом, без \, ваш код будет выглядеть следующим образомproc1.FileName = "C:\\Windows\\System32\\cmd.exe";
Джеймс Ко
1
Следует отметить, что proc1.Verb = "runas";этот процесс запускается с повышенными привилегиями ... Это не всегда задумано.
Диней
1
Как сделать так, чтобы это окно cmd не закрывалось после его завершения?
Hrvoje T
1
Я обнаружил, что вызов 'пути к компакт-диску' вместе с '&&' с другими командами в строке всегда выполняется последним, даже если он был первым. your: 'proc1.WorkingDirectory = @ "C: \ Windows \ System32";' было очень полезно! Спасибо!
Нозим Туракулов
11

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

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();
Мэтт Боннесс
источник
Если бы я хотел скомпилировать это в отдельное консольное приложение, какой другой код нужно было бы добавить, чтобы он работал? (Я новичок во всем этом программировании, только сделал несколько сценариев). Я использую csc.exe кстати.
script'n'code
@copyitright Пространство имен и класс. Если вы просто создадите новый проект, они будут созданы для вас.
coinbird
Ах. ничего. если вы используете cmd.exeприложение, вы можете передавать команды в качестве аргументов.
Зак Смит
Для потомков: я хотел, чтобы процесс запустился echo Hello World!и отобразил вывод команды в появившемся окне cmd. Так что я пробовал: Filename = @"echo", Arguments = "Hello World!", UseShellExecute = false, RedirectStandardOuput = false, CreateNoWindow = false. Это позволило окну cmd родительского приложения отображать «Hello World!» (что имеет смысл, потому что stdout не был перенаправлен на дочерний процесс).
Мин Чан
10

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

Этот метод я использую для объединения файлов (в данном случае это 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);
            }
        }
    }
}
CarllDev
источник
9

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

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

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

/ K

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

Uniquedesign
источник
Ницца. Нашел эту документацию для cmdкоманды и ее параметров.
Пий
8

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

Охотник за экземплярами
источник
11
Загрузка целых файлов в память просто для добавления друг к другу не очень эффективна, особенно если файлы достаточно велики.
Константин Спирин
7
Попробуйте взглянуть на дух ответа. Дело в том, что в .NET более чем достаточно классов и функций ввода-вывода, чтобы сделать это без вызова оболочки ОС. Отдельные функции, которые я упомянул, могут быть не самыми лучшими, но они были простейшими. Нет никакого смысла вызывать оболочку, чтобы сделать это.
Охотник за экземплярами
7

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

var stdout = new Cli("cmd")
         .Execute("copy /b Image1.jpg + Archive.rar Image2.jpg")
         .StandardOutput;
Tyrrrz
источник
Я проголосовал за это ... но репо сейчас, похоже, отсутствует:Unable to find package 'CliWrap' at source
Зак Смит
1
@ZachSmith не уверен, что вы имеете в виду, nuget.org/packages/CliWrap, кажется, работает нормально. Оригинальная ссылка тоже.
Тырррз
Ах. Извините ... по какой-то причине, когда я не смог подключиться к своему репозиторию Nuget через vpn, я не смог установить этот пакет. nuget до сих пор остается для меня загадкой. Должно быть, это неправильно настроено
Зак Смит
5

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

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
источник
5

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

    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
источник
2

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

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);
Владимир Верлег
источник
1

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

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

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

Process.Start("file_name.bat")

XMMR12
источник
если вы хотите скрыть cmd во время работы, вы можете использовать простой код Visual Basic в .vbsрасширении формата, код:CreateObject("Wscript.Shell").Run "filename.bat",0,True
XMMR12