我正在尝试在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)
我做错了什么?
答案 0 :(得分:162)
这应该有效。您可以尝试转储输出和错误流的内容,以便了解正在发生的事情:
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 *
它turns out如果同步读取流,则可以通过在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();
}
答案 1 :(得分:119)
System.Diagnostics.Process.Start("c:\\batchfilename.bat");
这个简单的行将执行批处理文件。
答案 2 :(得分:16)
在得到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();
}
答案 3 :(得分:13)
工作正常。我测试了这样:
String command = @"C:\Doit.bat";
ProcessInfo = new ProcessStartInfo("cmd.exe", "/c " + command);
// ProcessInfo.CreateNoWindow = true;
我注意到关掉了窗户,所以我可以看到它跑了。
答案 4 :(得分:9)
这是示例c#代码,它们向bat / cmd文件发送2个参数以回答此 question 。
注释:如何传递参数并读取命令执行的结果?
选项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();
}
}
}
答案 5 :(得分:3)
下面的代码对我来说很好
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...");
}
答案 6 :(得分:1)
您是否尝试过以管理员身份启动它?
,如果您使用它,请以管理员身份启动Visual Studio,因为使用.bat
文件需要这些权限。
答案 7 :(得分:1)
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());
}
}
答案 8 :(得分:0)
我想要一种更直接可用的东西,其中没有组织特定的硬编码字符串值。我提供以下内容作为直接可重用的代码块。较小的缺点是在拨打电话时需要确定并传递工作文件夹。
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#测试设置代码的一部分运行。环境重置批处理文件将测试用例文件移回输入文件夹,清理输出文件夹等,以进入适当的测试开始状态以进行测试。如果文件夹名称中有空格(“ Program Files”,有人吗?),QuotesAround方法只是在命令行两边加上引号。它的全部是这样:私有字符串QuotesAround(字符串输入){返回“ \”“ +输入+” \“”;}
希望有些人觉得这很有用,如果您的情况类似于我的情况,则可以节省几分钟。
答案 9 :(得分:0)
System.Diagnostics.Process.Start(BatchFileName, Parameters);
我知道这将适用于批处理文件和参数,但是不知道如何在C#中获得结果。 通常,输出是在批处理文件中定义的。
答案 10 :(得分:0)
使用先前提出的解决方案,我一直努力使多个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();
}
答案 11 :(得分:0)
使用CliWrap:
var result = await Cli.Wrap("foobar.bat").ExecuteBufferedAsync();
var exitCode = result.ExitCode;
var stdOut = result.StandardOutput;