C# 在C中执行批处理文件#

C# 在C中执行批处理文件#,c#,batch-file,process,processstartinfo,C#,Batch File,Process,Processstartinfo,我正试图用C#执行一个批处理文件,但我没有得到任何运气 我在网上找到了很多这样做的例子,但对我来说不起作用 public void ExecuteCommand(string command) { int ExitCode; ProcessStartInfo ProcessInfo; Process Process; ProcessInfo = new ProcessStartInfo("cmd.exe", "/c " + command); Proce

我正试图用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
中)以及它应该处理的一些文件。(示例:
txtmipulator file1.txt file2.txt file3.txt
)。当我手动执行批处理文件时,它工作正常

在执行代码时,它会给我一个
**ExitCode:1**(针对一般错误的捕获)


我做错了什么?

它工作正常。我是这样测试的:

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

ProcessInfo = new ProcessStartInfo("cmd.exe", "/c " + command);
// ProcessInfo.CreateNoWindow = true;
    // 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);

我评论说关闭窗口,这样我就可以看到它运行了。

这应该行得通。您可以尝试转储输出和错误流的内容,以了解发生了什么:

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
之前同步读取,或者依次同步读取
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();
}

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

此简单行将执行批处理文件。

您是否尝试以管理员身份启动它?如果使用Visual Studio,请以管理员身份启动它,因为使用
.bat
文件需要这些权限。

下面的代码对我来说很好

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

我想要一些更直接可用的东西,而不需要特定于组织的硬编码字符串值。我将以下内容作为可直接重用的代码块提供。次要的缺点是打电话时需要确定并传递工作文件夹

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();
        }
这样称呼:

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

ProcessInfo = new ProcessStartInfo("cmd.exe", "/c " + command);
// ProcessInfo.CreateNoWindow = true;
    // 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方法只是在命令行周围加上引号,以防文件夹名(“程序文件”,有人吗?)中有空格。它的全部内容是:私有字符串QuotesAround(字符串输入){return“\”“+input+”\”“;}


如果您的场景与我的类似,希望有些人觉得这很有用,并节省几分钟时间。

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

我知道这适用于批处理文件和参数,但不知道如何在C#中获得结果。 通常,输出是在批处理文件中定义的。

这里是示例c代码,它向bat/cmd文件发送两个参数以回答此问题


注释:如何传递参数并读取命令执行的结果

/通过

选项1:不隐藏控制台窗口、传递参数和不获取输出

  • 这是来自此/作者的编辑

选项2:隐藏控制台窗口、传递参数和获取输出




对于以前提出的解决方案,我很难在一个循环中执行多个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();
        }
    
    使用:

    var result=wait Cli.Wrap(“foobar.bat”).ExecuteBufferedAsync();
    var exitCode=result.exitCode;
    var stdOut=result.StandardOutput;
    
    您不显示什么是
    命令。如果它包含带空格的路径,则需要在路径周围加引号。@Jon我已经这样做了,这不是问题所在。谢谢你的意见!批处理文件中的某些内容失败了吗?您可能需要为您的进程设置WorkingDirectory(或该属性被调用的任何内容)。好的,当我手动执行命令中的代码(Start-->Run)时,它会正确运行。我现在已经添加了WorkingDirectory并将其设置为system32,但仍然得到错误代码:1添加这两条语句ExitCode=Process.ExitCode;和Process.Close();非常有帮助。谢谢!现在我可以看到错误是什么了。“C:\Windows\System32\txtmipulator.bat不被识别为内部或外部命令、程序或批处理文件”(翻译自荷兰语),这是一个奇数。因为当我从命令行运行txtmipulator时,它执行得非常完美。我能够重新创建您的问题,请查看答案中的添加内容。当我运行“pg_dump…>dumpfile”将27 GB数据库转储到dumpfileHow时,此方法不适用
    
        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();
        }