前段时间,遇到一个需求,须要解压文件,而且执行里面的 bat 文件。还须要获取执行进度,而且在错误的时候,中断执行。在这期间,在网上查找了许多的实例,不断地尝试,兜兜转转的绕了一大圈,记录一下走过的一些坑。
shell
我最开始想到的这个方法,最简单,不须要考虑bat的变量,脚本命令等如@ECHO OFF
,至关于双击执行了这个脚本文件。可是存在一个问题就是,没法展现执行进度,因此放弃了。windows
using (Process myPro = new Process()) { myPro.StartInfo.FileName = Path.Combine(dirPath, batFilePath); myPro.StartInfo.UseShellExecute = false; myPro.StartInfo.CreateNoWindow = true; myPro.Start(); myPro.WaitForExit(); }
至关于打开了一个cmd.exe的窗口,而后在这个窗体里,一行一行的输入进去命令执行。以下图:
异步
这样有的好处就是,bat文件不用大修改:操作系统
Bslot_images_path
变量,在脚本文件中大量使用;ping -n 6 127.0.0.1
这个命令;缺点有三点:3d
%~dp0
只能够用在批处理文件中,它是由它所在的批处理文件的目录位置决定的,是批处理文件所在的盘符:+路径。&exit
,才能获取。不然执行p.StandardOutput.ReadToEnd();
会出现假死情况。waiting for any device等状况,只能ctrl+c强制退出。下面是网上找的一个简单的演示版本,关键就是循环输入处,没法实时的得到执行的结果;另外就是超时时间问题。日志
static void Main(string[] args) { Console.WriteLine("请输入要执行的命令:"); string strInput = Console.ReadLine(); Process p = new Process(); p.StartInfo.FileName = "cmd.exe"; //设置要启动的应用程序 p.StartInfo.UseShellExecute = false; //是否使用操做系统shell启动 p.StartInfo.RedirectStandardInput = true; // 接受来自调用程序的输入信息 p.StartInfo.RedirectStandardOutput = true; //输出信息 p.StartInfo.RedirectStandardError = true; // 输出错误 p.StartInfo.CreateNoWindow = true; //不显示程序窗口 p.Start(); //启动程序 p.StandardInput.WriteLine(strInput+"&exit"); //向cmd窗口发送输入信息,若是批处理,须要这里作循环输入 p.StandardInput.AutoFlush=true; string strOuput = p.StandardOutput.ReadToEnd(); //获取输出信息 p.WaitForExit(60 * 1000); //等待程序执行完退出进程,cmd.exe超时时间 p.Close(); Console.WriteLine(strOuput); Console.ReadKey(); }
这个咋一看起来和用 cmd.exe 逐行执行命令
很像,这个不一样点就是 把每一个命令的exe文件单独拿出来执行,而不是使用cmd.exe
来执行。而且能够给每一条命令,设置一个单独的超时时间。code
须要注意的点,从新编辑 bat 批处理文件:blog
批处理独有的命令
,缘由为没法变成exe执行(如:"@SET BASEPATH=%~dp0","@ECHO OFF"等);windows系统命令
,缘由为工做目录
非系统PATH,没法找到系统exe(如:"ping -n 6 127.0.0.1","cd A_Debug"等);具体值
,目的是为了,变成能够单独一条拿出来执行的命令(如:"fastboot flash boot0 "A_Debug/boot0.img" ");空白行
以及等待用户操做
的命令(如:"pause > nul")命令须要拆分:exe执行程序
,参数
,超时时长
三部分;如:“fastboot flash boot0 "A_Debug/boot0.img" ” 拆分为:进程
而后把拆分后的参数,传入执行,具体执行命令的代码以下。事件
private List<string> Shell(string exeFile, string command, int timeout, string workingDir, out int exitCode) { List<string> response = new List<string>(); List<string> output = new List<string>(); List<string> error = new List<string>(); Process process = new Process(); process.StartInfo.FileName = exeFile; //设置要启动的应用程序,如:fastboot process.StartInfo.Arguments = command; // 设置应用程序参数,如: flash boot0 "A_Debug/boot0.img" process.StartInfo.UseShellExecute = false; process.StartInfo.RedirectStandardInput = true; process.StartInfo.RedirectStandardOutput = true; process.StartInfo.RedirectStandardError = true; process.StartInfo.CreateNoWindow = true; process.EnableRaisingEvents = true; // 获取或设置在进程终止时是否应激发 Exited 事件;不管是正常退出仍是异常退出。 process.StartInfo.WorkingDirectory = workingDir; // **重点**,工做目录,必须是 bat 批处理文件所在的目录 process.OutputDataReceived += (object sender, DataReceivedEventArgs e) => Redirected(output, sender, e); process.ErrorDataReceived += (object sender, DataReceivedEventArgs e) => Redirected(error, sender, e); process.Start(); process.BeginOutputReadLine(); // 开启异步读取输出操做 process.BeginErrorReadLine(); // 开启异步读取错误操做 bool exited = process.WaitForExit(timeout); if (!exited) { process.Kill(); // 经过超时判断是否执行失败,很可能为假死状态。 // 记录日志 response.Add("Error: timed out"); } response.AddRange(output); response.AddRange(error); exitCode = process.ExitCode; // 0 为正常退出。 return response; } private void Redirected(List<string> dataList, object sender, DataReceivedEventArgs e) { if (e.Data != null){ dataList.Add(e.Data); } }