前段時間,遇到一個需求,須要解壓文件,而且執行裏面的 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); } }