Я пытаюсь выполнить командный файл на C #, но мне это не удается.
Я нашел в Интернете несколько примеров этого, но у меня это не работает.
public void ExecuteCommand(string command)
{
int ExitCode;
ProcessStartInfo ProcessInfo;
Process Process;
ProcessInfo = new ProcessStartInfo("cmd.exe", "/c " + command);
ProcessInfo.CreateNoWindow = true;
ProcessInfo.UseShellExecute = false;
Process = Process.Start(ProcessInfo);
Process.WaitForExit();
ExitCode = Process.ExitCode;
Process.Close();
MessageBox.Show("ExitCode: " + ExitCode.ToString(), "ExecuteCommand");
}
Командная строка содержит имя командного файла (хранящегося в system32
) и некоторых файлов, с которыми он должен работать. (Пример:) txtmanipulator file1.txt file2.txt file3.txt
. Когда я запускаю командный файл вручную, он работает правильно.
При выполнении кода он дает мне **ExitCode: 1** (Catch all for general errors)
Что я делаю не так?
c#
batch-file
process
processstartinfo
Вессель Т.
источник
источник
command
есть. Если он содержит пути с пробелами, вам нужно будет заключить их в кавычки.Ответы:
Это должно работать. Вы можете попытаться выгрузить содержимое потоков вывода и ошибок, чтобы узнать, что происходит:
static void ExecuteCommand(string command) { int exitCode; ProcessStartInfo processInfo; Process process; processInfo = new ProcessStartInfo("cmd.exe", "/c " + command); processInfo.CreateNoWindow = true; processInfo.UseShellExecute = false; // *** Redirect the output *** processInfo.RedirectStandardError = true; processInfo.RedirectStandardOutput = true; process = Process.Start(processInfo); process.WaitForExit(); // *** Read the streams *** // Warning: This approach can lead to deadlocks, see Edit #2 string output = process.StandardOutput.ReadToEnd(); string error = process.StandardError.ReadToEnd(); exitCode = process.ExitCode; Console.WriteLine("output>>" + (String.IsNullOrEmpty(output) ? "(none)" : output)); Console.WriteLine("error>>" + (String.IsNullOrEmpty(error) ? "(none)" : error)); Console.WriteLine("ExitCode: " + exitCode.ToString(), "ExecuteCommand"); process.Close(); } static void Main() { ExecuteCommand("echo testing"); }
* РЕДАКТИРОВАТЬ *
Учитывая дополнительную информацию в вашем комментарии ниже, я смог воссоздать проблему. Похоже, что есть некоторые настройки безопасности, которые приводят к такому поведению (не исследовали это подробно).
Это делает работу , если пакетный файл не находится в
C:\Windows\System32
. Попробуйте переместить его в другое место, например, в место вашего исполняемого файла. Обратите внимание, что хранение пользовательских командных файлов или исполняемых файлов в каталоге Windows в любом случае является плохой практикой.* EDIT 2 * Это получается, что если потоки считываются синхронно, тупиковый может происходить либо путем считывания синхронно перед тем
WaitForExit
или путем считывания какstderr
иstdout
синхронно друг за другом.Этого не должно происходить, если вместо этого используются методы асинхронного чтения, как в следующем примере:
static void ExecuteCommand(string command) { var processInfo = new ProcessStartInfo("cmd.exe", "/c " + command); processInfo.CreateNoWindow = true; processInfo.UseShellExecute = false; processInfo.RedirectStandardError = true; processInfo.RedirectStandardOutput = true; var process = Process.Start(processInfo); process.OutputDataReceived += (object sender, DataReceivedEventArgs e) => Console.WriteLine("output>>" + e.Data); process.BeginOutputReadLine(); process.ErrorDataReceived += (object sender, DataReceivedEventArgs e) => Console.WriteLine("error>>" + e.Data); process.BeginErrorReadLine(); process.WaitForExit(); Console.WriteLine("ExitCode: {0}", process.ExitCode); process.Close(); }
источник
System.Diagnostics.Process.Start("c:\\batchfilename.bat");
эта простая строка выполнит командный файл.
источник
После большой помощи Steinar у меня сработало следующее:
public void ExecuteCommand(string command) { int ExitCode; ProcessStartInfo ProcessInfo; Process process; ProcessInfo = new ProcessStartInfo(Application.StartupPath + "\\txtmanipulator\\txtmanipulator.bat", command); ProcessInfo.CreateNoWindow = true; ProcessInfo.UseShellExecute = false; ProcessInfo.WorkingDirectory = Application.StartupPath + "\\txtmanipulator"; // *** Redirect the output *** ProcessInfo.RedirectStandardError = true; ProcessInfo.RedirectStandardOutput = true; process = Process.Start(ProcessInfo); process.WaitForExit(); // *** Read the streams *** string output = process.StandardOutput.ReadToEnd(); string error = process.StandardError.ReadToEnd(); ExitCode = process.ExitCode; MessageBox.Show("output>>" + (String.IsNullOrEmpty(output) ? "(none)" : output)); MessageBox.Show("error>>" + (String.IsNullOrEmpty(error) ? "(none)" : error)); MessageBox.Show("ExitCode: " + ExitCode.ToString(), "ExecuteCommand"); process.Close(); }
источник
~%dp0
. ДобавлениеProcessInfo.WorkingDirectory
исправленного.command
если вы вызываете файл BAT напрямую?command
параметры могут использоваться для отправки аргументов в файл BAT, это не то, что здесь показывает код. Фактически он вообще не используется. И если бы это было так, вероятно, его следовало бы назватьarguments
вместо этого.command
используется вnew ProcessStartInfo
звонке.Работает нормально. Я тестировал это так:
String command = @"C:\Doit.bat"; ProcessInfo = new ProcessStartInfo("cmd.exe", "/c " + command); // ProcessInfo.CreateNoWindow = true;
Я прокомментировал отключение окна, чтобы ВИДЕТЬ его запуск.
источник
Вот пример кода C #, который отправляет 2 параметра в файл bat / cmd для ответа на этот вопрос .
Комментарий: как передать параметры и прочитать результат выполнения команды?
/ Автор @Janatbek Sharsheyev
using System; using System.Diagnostics; namespace ConsoleApplication { class Program { static void Main(string[] args) { System.Diagnostics.Process.Start(@"c:\batchfilename.bat", "\"1st\" \"2nd\""); } } }
using System; using System.Diagnostics; namespace ConsoleApplication { class Program { static void Main(string[] args) { var process = new Process(); var startinfo = new ProcessStartInfo(@"c:\batchfilename.bat", "\"1st_arg\" \"2nd_arg\" \"3rd_arg\""); startinfo.RedirectStandardOutput = true; startinfo.UseShellExecute = false; process.StartInfo = startinfo; process.OutputDataReceived += (sender, argsx) => Console.WriteLine(argsx.Data); // do whatever processing you need to do in this handler process.Start(); process.BeginOutputReadLine(); process.WaitForExit(); } } }
источник
Код ниже отлично работал у меня
using System.Diagnostics; public void ExecuteBatFile() { Process proc = null; string _batDir = string.Format(@"C:\"); proc = new Process(); proc.StartInfo.WorkingDirectory = _batDir; proc.StartInfo.FileName = "myfile.bat"; proc.StartInfo.CreateNoWindow = false; proc.Start(); proc.WaitForExit(); ExitCode = proc.ExitCode; proc.Close(); MessageBox.Show("Bat file executed..."); }
источник
using System.Diagnostics; private void ExecuteBatFile() { Process proc = null; try { string targetDir = string.Format(@"D:\mydir"); //this is where mybatch.bat lies proc = new Process(); proc.StartInfo.WorkingDirectory = targetDir; proc.StartInfo.FileName = "lorenzo.bat"; proc.StartInfo.Arguments = string.Format("10"); //this is argument proc.StartInfo.CreateNoWindow = false; proc.StartInfo.WindowStyle = ProcessWindowStyle.Hidden; //this is for hiding the cmd window...so execution will happen in back ground. proc.Start(); proc.WaitForExit(); } catch (Exception ex) { Console.WriteLine("Exception Occurred :{0},{1}", ex.Message, ex.StackTrace.ToString()); } }
источник
Вы пробовали запустить его от имени администратора? Запустите Visual Studio от имени администратора, если вы его используете, потому что для работы с
.bat
файлами требуются эти права.источник
Мне нужно было что-то более удобное для использования без жестко заданных строковых значений для конкретной организации. Я предлагаю следующий фрагмент кода многократного использования. Незначительный недостаток - необходимость определения и передачи рабочей папки при звонке.
public static void ExecuteCommand(string command, string workingFolder) { int ExitCode; ProcessStartInfo ProcessInfo; Process process; ProcessInfo = new ProcessStartInfo("cmd.exe", "/c " + command); ProcessInfo.CreateNoWindow = true; ProcessInfo.UseShellExecute = false; ProcessInfo.WorkingDirectory = workingFolder; // *** Redirect the output *** ProcessInfo.RedirectStandardError = true; ProcessInfo.RedirectStandardOutput = true; process = Process.Start(ProcessInfo); process.WaitForExit(); // *** Read the streams *** string output = process.StandardOutput.ReadToEnd(); string error = process.StandardError.ReadToEnd(); ExitCode = process.ExitCode; MessageBox.Show("output>>" + (String.IsNullOrEmpty(output) ? "(none)" : output)); MessageBox.Show("error>>" + (String.IsNullOrEmpty(error) ? "(none)" : error)); MessageBox.Show("ExitCode: " + ExitCode.ToString(), "ExecuteCommand"); process.Close(); }
Вызывается так:
// This will get the current WORKING directory (i.e. \bin\Debug) string workingDirectory = Environment.CurrentDirectory; // This will get the current PROJECT directory string projectDirectory = Directory.GetParent(workingDirectory).Parent.FullName; string commandToExecute = Path.Combine(projectDirectory, "TestSetup", "WreckersTestSetupQA.bat"); string workingFolder = Path.GetDirectoryName(commandToExecute); commandToExecute = QuotesAround(commandToExecute); ExecuteCommand(commandToExecute, workingFolder);
В этом примере из Visual Studio 2017 в рамках тестового запуска я хочу запустить пакетный файл сброса среды перед выполнением некоторых тестов. (SpecFlow + xUnit). Мне надоели лишние шаги для ручного запуска файла bat отдельно, и я хотел просто запустить файл bat как часть кода настройки теста C #. Пакетный файл сброса среды перемещает файлы тестовых примеров обратно во входную папку, очищает выходные папки и т. Д., Чтобы перейти в правильное начальное состояние теста для тестирования. Метод QuotesAround просто помещает в кавычки командную строку на случай, если в именах папок есть пробелы («Program Files», кто-нибудь?). Все, что в нем, это: приватная строка QuotesAround (строковый ввод) {return "\" "+ input +" \ "";}
Надеюсь, что некоторые сочтут это полезным и сэкономят несколько минут, если ваш сценарий похож на мой.
источник
С помощью ранее предложенных решений я изо всех сил пытался выполнить несколько команд npm в цикле и получить все выходные данные в окне консоли.
Наконец, он начал работать после того, как я объединил все из предыдущих комментариев, но перестроил поток выполнения кода.
Я заметил, что подписка на события была выполнена слишком поздно (после того, как процесс уже начался), и поэтому некоторые выходные данные не были захвачены.
Код ниже теперь делает следующее:
Код был протестирован на наличие взаимоблокировок, хотя он является синхронным (выполнение одного процесса за раз), поэтому я не могу гарантировать, что произойдет, если это будет выполняться параллельно.
static void RunCommand(string command, string workingDirectory) { Process process = new Process { StartInfo = new ProcessStartInfo("cmd.exe", $"/c {command}") { WorkingDirectory = workingDirectory, CreateNoWindow = true, UseShellExecute = false, RedirectStandardError = true, RedirectStandardOutput = true } }; process.OutputDataReceived += (object sender, DataReceivedEventArgs e) => Console.WriteLine("output :: " + e.Data); process.ErrorDataReceived += (object sender, DataReceivedEventArgs e) => Console.WriteLine("error :: " + e.Data); process.Start(); process.BeginOutputReadLine(); process.BeginErrorReadLine(); process.WaitForExit(); Console.WriteLine("ExitCode: {0}", process.ExitCode); process.Close(); }
источник
Использование CliWrap :
var result = await Cli.Wrap("foobar.bat").ExecuteBufferedAsync(); var exitCode = result.ExitCode; var stdOut = result.StandardOutput;
источник
System.Diagnostics.Process.Start(BatchFileName, Parameters);
Я знаю, что это сработает для командного файла и параметров, но нет идей, как получить результаты на C #. Обычно выходы определяются в пакетном файле.
источник