簡體   English   中英

在 C# 中執行批處理文件

[英]Executing Batch File in C#

我正在嘗試在 C# 中執行一個批處理文件,但我沒有得到任何運氣。

我在 Internet 上找到了多個這樣做的示例,但它對我不起作用。

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)

我究竟做錯了什么?

這應該有效。 您可以嘗試轉儲輸出和錯誤流的內容,以了解發生了什么:

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 目錄中無論如何都是不好的做法。

* 編輯 2 * 事實證明,如果同步讀取流,可能會發生死鎖,要么在WaitForExit之前同步讀取,要么一個接一個同步讀取stderrstdout

如果改用異步讀取方法,則不應發生這種情況,如下例所示:

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

它工作正常。 我是這樣測試的:

String command = @"C:\Doit.bat";

ProcessInfo = new ProcessStartInfo("cmd.exe", "/c " + command);
// ProcessInfo.CreateNoWindow = true;

我注釋掉關閉窗口,以便我可以看到它運行。

這是示例 c# 代碼,它們將 2 個參數發送到 bat/cmd 文件以回答這個問題

評論:如何傳遞參數並讀取命令執行結果?

/by @Janatbek Sharsheyev

選項 1:不隱藏控制台窗口,傳遞參數且不獲取輸出

using System;
using System.Diagnostics;


namespace ConsoleApplication
{
    class Program
    { 
        static void Main(string[] args)
        {
         System.Diagnostics.Process.Start(@"c:\batchfilename.bat", "\"1st\" \"2nd\"");
        }
    }
}

選項 2:隱藏控制台窗口,傳遞參數並獲取輸出


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文件需要這些權限。

使用以前提出的解決方案,我一直在努力讓多個 npm 命令在循環中執行並在控制台窗口上獲得所有輸出。

在我結合了之前評論中的所有內容后,它終於開始工作了,但重新安排了代碼執行流程。

我注意到的是事件訂閱完成得太晚了(在流程已經開始之后),因此一些輸出沒有被捕獲。

下面的代碼現在執行以下操作:

  1. 在流程開始之前訂閱事件,從而確保不會丟失任何輸出。
  2. 進程一開始就開始從輸出中讀取。

代碼已經針對死鎖進行了測試,盡管它是同步的(當時一個進程執行),所以我不能保證如果並行運行會發生什么。

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

我想要一些更直接可用的東西,而沒有特定於組織的硬編碼字符串值。 我提供以下作為可直接重用的代碼塊。 次要缺點是在撥打電話時需要確定並傳遞工作文件夾。

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 方法只是在命令行周圍加上引號,以防文件夾名稱中有空格(“程序文件”,有人嗎?)。 它的全部內容是: private string QuotesAround(string input) {return "\\"" + input + "\\"";}

如果您的場景與我的相似,希望有些人覺得這很有用並節省幾分鍾。

使用CliWrap

var result = await Cli.Wrap("foobar.bat").ExecuteBufferedAsync();

var exitCode = result.ExitCode;
var stdOut = result.StandardOutput;

System.Diagnostics.Process.Start(BatchFileName, Parameters);

我知道這適用於批處理文件和參數,但不知道如何在 C# 中獲得結果。 通常,輸出在批處理文件中定義。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM