咱們可能會遇到須要在程序中執行一些系統命令,來獲取一些信息;或者調用shell腳本。.NET Core 目前已經能夠跨平臺執行,那麼它如何跨平臺執行命令呢,請看下面的講解。linux
咱們主要用到的兩個類就是 ProcessStartInfo
和 Process
,他們的用法和.NET Framework下是同樣的。git
ProcessStartInfo
主要設置一些咱們須要建立的進程的參數。好比須要啓動的應用程序的文件名,參數等等。github
它有三個構造方法:shell
public ProcessStartInfo(); public ProcessStartInfo(string fileName); public ProcessStartInfo(string fileName, string arguments);
fileName
:用於啓動進程的應用程序。windows
arguments
:在進程啓動時傳遞給應用程序的命令行參數。緩存
CreateNoWindow
:指示是否在新窗口中啓動進程。bash
RedirectStandardError
:指示應用程序的錯誤輸出是否寫入到流中。異步
RedirectStandardInput
:指示是否從應用程序讀取應用程序的輸入流。測試
RedirectStandardOutput
:指示應用程序的文本輸出是否寫入流。編碼
StandardErrorEncoding
:錯誤輸出內容編碼。
StandardOutputEncoding
:文本輸出內容編碼。
UseShellExecute
:指示是否使用操做系統shell啓動進程。若是啓動進程時使用shell,則爲true; 若是應該直接從可執行文件建立進程,則爲false。 默認值是true。
該類並無定義本身的方法,由於它主要設置一些建立進程須要的參數信息。
該類的主要做用是提供對本地和遠程進程的訪問,並使你可以啓動和中止本地系統進程。
ExitCode
:獲取退出代碼。0表示正常, 非0表示非正常退出。
ExitTime
:獲取關聯進程退出的時間。
StartTime
:獲取關聯進程啓動的時間。
HasExited
:獲取一個值,指示相關進程是否已終止。
MachineName
:獲取運行關聯進程的計算機的名稱。
SessionId
:獲取關聯進程的終端服務會話標識符。
StandardError
:獲取讀取應用程序錯誤輸出的流。
StandardInput
:獲取應用程序輸入內容的流。
StandardOutput
:獲取用於讀取應用程序文本輸出的流。
Threads
:獲取關聯進程中正在運行的線程集合。
Start
:啓動進程
BeginErrorReadLine
:異步開始讀取應用錯誤輸出。
BeginOutputReadLine
:異步開始讀取應用標準輸出。
CancelErrorRead
:取消讀取錯誤輸出。
CancelOutputRead
:取消讀取標準輸出。
Close
:釋放與此組件關聯的全部資源。
CloseMainWindow
:經過向其主窗口發送關閉消息來關閉具備用戶界面的進程。
Kill
:當即中止關聯的進程。
Refresh
:放棄已經在進程中緩存的關聯進程的任何信息。
WaitForExit
:等待關聯進程退出,能夠設置超時時間,如不設置則一直等待。
一共有三個事件:
ErrorDataReceived
:接收到關聯進程輸出錯誤數據。
OutputDataReceived
:接收到關聯進程輸出標準數據。
Exited
:關聯進程退出
這裏我選擇.NET Core帶的 dotnet --info
輸出.NET Core SDK&Runtime相關的信息。
咱們經過cmd執行會收到下面的信息:
編寫的代碼以下:
static void Main() { //建立一個ProcessStartInfo對象 使用系統shell 指定命令和參數 設置標準輸出 var psi = new ProcessStartInfo("dotnet", "--info") {RedirectStandardOutput = true}; //啓動 var proc=Process.Start(psi); if (proc == null) { Console.WriteLine("Can not exec."); } else { Console.WriteLine("-------------Start read standard output--------------"); //開始讀取 using (var sr = proc.StandardOutput) { while (!sr.EndOfStream) { Console.WriteLine(sr.ReadLine()); } if (!proc.HasExited) { proc.Kill(); } } Console.WriteLine("---------------Read end------------------"); Console.WriteLine($"Total execute time :{(proc.ExitTime-proc.StartTime).TotalMilliseconds} ms"); Console.WriteLine($"Exited Code : {proc.ExitCode}"); } }
執行結果以下:
從執行結果能夠看出,咱們經過編寫的程序來執行dotnet --info
命令獲取的結果幾乎同樣,只有第一行的提示,咱們經過cmd執行命令輸出的是中文,咱們經過程序調用執行輸出的是英文,這個問題,有興趣的朋友能夠研究一下。
使用的系統環境爲CentOS 7.2,.NET Core sdk版本爲2.0.3。
直接執行命令結果以下:
我將代碼上傳到git server,而後在linux上clone而後執行結果以下:
能夠看到咱們獲取執行輸出是沒有問題的,可是獲取進程開始執行出錯了,沒法從進程檢索該信息,如今咱們移除統計執行時間的代碼:
這下咱們執行就沒有問題了。從這裏咱們能夠得出結論:因爲平臺的差別,獲取一些信息可能會出現異常,因此咱們實際必定要在多個平臺上測試。
我在OSX上的.NET Core SDK版本爲2.0.0 好久沒更新了。
直接執行命令:
從git Clone代碼,執行結果以下:
能夠看出咱們在OSX上執行是沒有問題的。
編寫腳本的主要邏輯爲輸出程序當前目錄結構,而後輸出一句話 「dotnet in 操做系統類型」
Windows: win.bat
@echo off dir echo "dotnet in Windows"
Linux: linux.sh
#!/bin/bash ls echo "dotnet in Linux"
OSX: OSX.sh
#!/bin/bash ls echo "dotnet in OSX"
我將全部的腳本都放在 項目根目錄/shell 文件夾下。
由於咱們須要根據不一樣的操做類型,選擇不一樣的腳原本進行執行,因此咱們須要在代碼裏面判斷一下操做系統類型。咱們能夠經過 RuntimeInformation.IsOSPlatform
來判斷。
static void Main() { string fileName="shell/"; //根據系統使用不一樣的shell文件 if (RuntimeInformation.IsOSPlatform(OSPlatform.Windows)) { fileName += "win.bat"; } else if (RuntimeInformation.IsOSPlatform(OSPlatform.Linux)) { fileName += "linux.sh"; } else { fileName += "OSX.sh"; } //建立一個ProcessStartInfo對象 使用系統shell 指定命令和參數 設置標準輸出 var psi = new ProcessStartInfo(fileName) { RedirectStandardOutput = true }; //啓動 var proc = Process.Start(psi); if (proc == null) { Console.WriteLine("Can not exec."); } else { Console.WriteLine("-------------Start read standard output--------------"); //開始讀取 using (var sr = proc.StandardOutput) { while (!sr.EndOfStream) { Console.WriteLine(sr.ReadLine()); } if (!proc.HasExited) { proc.Kill(); } } Console.WriteLine("---------------Read end------------------"); Console.WriteLine($"Exited Code : {proc.ExitCode}"); } }
在windows下運行是徹底正常的。
直接運行會報一個權限異常,以下:
使用命令加入執行權限:
chmod +x OSX.sh
而後再次執行:
能夠看到成功執行了腳本。
直接運行也是會有權限問題的:
一樣使用命令加入執行權限:
chmod +x linux.sh
而後再次執行:
能夠看到成功執行了咱們的腳本。
看見上面的例子,我都成功執行了,其實我踩了幾個坑,花了我很多時間來解決。
也就是這句話,放在sh腳本開頭
#!/bin/bash
否則程序執行的時候,讀取字符會出錯,形成執行異常。
但願本文能給你們帶來幫助,若有問題歡迎和我討論。
本文所用代碼地址:https://github.com/stulzq/BlogDemos/tree/master/DotnetCmd