.NET Core跨平臺(tái)執(zhí)行命令、腳本的方法詳細(xì)
一.前言
在工作中我們可能會(huì)遇到需要在程序中執(zhí)行一些系統(tǒng)命令,來(lái)獲取一些信息;或者調(diào)用shell腳本。.NET Core 目前已經(jīng)可以跨平臺(tái)執(zhí)行,那么它如何跨平臺(tái)執(zhí)行命令呢,請(qǐng)看下面的講解。話不多說(shuō)了,來(lái)一起看看詳細(xì)的介紹吧
二.ProcessStartInfo、Process 類介紹
我們主要用到的兩個(gè)類就是 ProcessStartInfo 和 Process ,他們的用法和.NET Framework下是一樣的。
1. ProcessStartInfo 類
ProcessStartInfo主要設(shè)置一些我們需要?jiǎng)?chuàng)建的進(jìn)程的參數(shù)。比如需要啟動(dòng)的應(yīng)用程序的文件名,參數(shù)等等。
(1)構(gòu)造方法
它有三個(gè)構(gòu)造方法:
public ProcessStartInfo(); public ProcessStartInfo(string fileName); public ProcessStartInfo(string fileName, string arguments);
fileName:用于啟動(dòng)進(jìn)程的應(yīng)用程序。
arguments:在進(jìn)程啟動(dòng)時(shí)傳遞給應(yīng)用程序的命令行參數(shù)。
(2)主要屬性
CreateNoWindow:指示是否在新窗口中啟動(dòng)進(jìn)程。
RedirectStandardError:指示應(yīng)用程序的錯(cuò)誤輸出是否寫(xiě)入到流中。
RedirectStandardInput:指示是否從應(yīng)用程序讀取應(yīng)用程序的輸入流。
RedirectStandardOutput:指示應(yīng)用程序的文本輸出是否寫(xiě)入流。
StandardErrorEncoding:錯(cuò)誤輸出內(nèi)容編碼。
StandardOutputEncoding:文本輸出內(nèi)容編碼。
UseShellExecute:指示是否使用操作系統(tǒng)shell啟動(dòng)進(jìn)程。如果啟動(dòng)進(jìn)程時(shí)使用shell,則為true; 如果應(yīng)該直接從可執(zhí)行文件創(chuàng)建進(jìn)程,則為false。 默認(rèn)值是true。
該類并沒(méi)有定義自己的方法,因?yàn)樗饕O(shè)置一些創(chuàng)建進(jìn)程需要的參數(shù)信息。
2. Process 類
該類的主要作用是提供對(duì)本地和遠(yuǎn)程進(jìn)程的訪問(wèn),并使你能夠啟動(dòng)和停止本地系統(tǒng)進(jìn)程。
(1).主要屬性
ExitCode:獲取退出代碼。0表示正常, 非0表示非正常退出。
ExitTime:獲取關(guān)聯(lián)進(jìn)程退出的時(shí)間。
StartTime:獲取關(guān)聯(lián)進(jìn)程啟動(dòng)的時(shí)間。
HasExited:獲取一個(gè)值,指示相關(guān)進(jìn)程是否已終止。
MachineName:獲取運(yùn)行關(guān)聯(lián)進(jìn)程的計(jì)算機(jī)的名稱。
SessionId:獲取關(guān)聯(lián)進(jìn)程的終端服務(wù)會(huì)話標(biāo)識(shí)符。
StandardError:獲取讀取應(yīng)用程序錯(cuò)誤輸出的流。
StandardInput:獲取應(yīng)用程序輸入內(nèi)容的流。
StandardOutput:獲取用于讀取應(yīng)用程序文本輸出的流。
Threads:獲取關(guān)聯(lián)進(jìn)程中正在運(yùn)行的線程集合。
(2).主要方法
Start :?jiǎn)?dòng)進(jìn)程
BeginErrorReadLine:異步開(kāi)始讀取應(yīng)用錯(cuò)誤輸出。
BeginOutputReadLine:異步開(kāi)始讀取應(yīng)用標(biāo)準(zhǔn)輸出。
CancelErrorRead:取消讀取錯(cuò)誤輸出。
CancelOutputRead:取消讀取標(biāo)準(zhǔn)輸出。
Close:釋放與此組件關(guān)聯(lián)的所有資源。
CloseMainWindow:通過(guò)向其主窗口發(fā)送關(guān)閉消息來(lái)關(guān)閉具有用戶界面的進(jìn)程。
Kill:立即停止關(guān)聯(lián)的進(jìn)程。
Refresh:放棄已經(jīng)在進(jìn)程中緩存的關(guān)聯(lián)進(jìn)程的任何信息。
WaitForExit:等待關(guān)聯(lián)進(jìn)程退出,可以設(shè)置超時(shí)時(shí)間,如不設(shè)置則一直等待。
(3)事件
一共有三個(gè)事件:
ErrorDataReceived:接收到關(guān)聯(lián)進(jìn)程輸出錯(cuò)誤數(shù)據(jù)。
OutputDataReceived:接收到關(guān)聯(lián)進(jìn)程輸出標(biāo)準(zhǔn)數(shù)據(jù)。
Exited:關(guān)聯(lián)進(jìn)程退出
三.在Windows OSX Linux 下執(zhí)行命令
這里我選擇.NET Core帶的 dotnet --info輸出.NET Core SDK&Runtime相關(guān)的信息。
我們通過(guò)cmd執(zhí)行會(huì)收到下面的信息:

1.編寫(xiě)代碼執(zhí)行命令
編寫(xiě)的代碼如下:
static void Main()
{
//創(chuàng)建一個(gè)ProcessStartInfo對(duì)象 使用系統(tǒng)shell 指定命令和參數(shù) 設(shè)置標(biāo)準(zhǔn)輸出
var psi = new ProcessStartInfo("dotnet", "--info") {RedirectStandardOutput = true};
//啟動(dòng)
var proc=Process.Start(psi);
if (proc == null)
{
Console.WriteLine("Can not exec.");
}
else
{
Console.WriteLine("-------------Start read standard output--------------");
//開(kāi)始讀取
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}");
}
}
執(zhí)行結(jié)果如下:

從執(zhí)行結(jié)果可以看出,我們通過(guò)編寫(xiě)的程序來(lái)執(zhí)行dotnet --info命令獲取的結(jié)果幾乎一樣,只有第一行的提示,我們通過(guò)cmd執(zhí)行命令輸出的是中文,我們通過(guò)程序調(diào)用執(zhí)行輸出的是英文,這個(gè)問(wèn)題,有興趣的朋友可以研究一下。
2.在Linux上執(zhí)行
使用的系統(tǒng)環(huán)境為CentOS 7.2,.NET Core sdk版本為2.0.3。
直接執(zhí)行命令結(jié)果如下:

我將代碼上傳到git server,然后在linux上clone然后執(zhí)行結(jié)果如下:

可以看到我們獲取執(zhí)行輸出是沒(méi)有問(wèn)題的,但是獲取進(jìn)程開(kāi)始執(zhí)行出錯(cuò)了,無(wú)法從進(jìn)程檢索該信息,現(xiàn)在我們移除統(tǒng)計(jì)執(zhí)行時(shí)間的代碼:

這下我們執(zhí)行就沒(méi)有問(wèn)題了。從這里我們可以得出結(jié)論:由于平臺(tái)的差異,獲取一些信息可能會(huì)出現(xiàn)異常,所以我們實(shí)際一定要在多個(gè)平臺(tái)上測(cè)試。
3.在OSX上運(yùn)行
我在OSX上的.NET Core SDK版本為2.0.0 很久沒(méi)更新了。
直接執(zhí)行命令:

從git Clone代碼,執(zhí)行結(jié)果如下:

可以看出我們?cè)贠SX上執(zhí)行是沒(méi)有問(wèn)題的。
四.在Windows OSX Linux 下執(zhí)行腳本1.編寫(xiě)測(cè)試腳本
編寫(xiě)腳本的主要邏輯為輸出程序當(dāng)前目錄結(jié)構(gòu),然后輸出一句話 “dotnet in 操作系統(tǒng)類型”
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"
2.編寫(xiě)測(cè)試代碼
我將所有的腳本都放在 項(xiàng)目根目錄/shell 文件夾下。

因?yàn)槲覀冃枰鶕?jù)不同的操作類型,選擇不同的腳本來(lái)進(jìn)行執(zhí)行,所以我們需要在代碼里面判斷一下操作系統(tǒng)類型。我們可以通過(guò) RuntimeInformation.IsOSPlatform來(lái)判斷。
static void Main()
{
string fileName="shell/";
//根據(jù)系統(tǒng)使用不同的shell文件
if (RuntimeInformation.IsOSPlatform(OSPlatform.Windows))
{
fileName += "win.bat";
}
else if (RuntimeInformation.IsOSPlatform(OSPlatform.Linux))
{
fileName += "linux.sh";
}
else
{
fileName += "OSX.sh";
}
//創(chuàng)建一個(gè)ProcessStartInfo對(duì)象 使用系統(tǒng)shell 指定命令和參數(shù) 設(shè)置標(biāo)準(zhǔn)輸出
var psi = new ProcessStartInfo(fileName) { RedirectStandardOutput = true };
//啟動(dòng)
var proc = Process.Start(psi);
if (proc == null)
{
Console.WriteLine("Can not exec.");
}
else
{
Console.WriteLine("-------------Start read standard output--------------");
//開(kāi)始讀取
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}");
}
}
3.在Windows下運(yùn)行

在windows下運(yùn)行是完全正常的。
4.在OSX運(yùn)行
直接運(yùn)行會(huì)報(bào)一個(gè)權(quán)限異常,如下:

使用命令加入執(zhí)行權(quán)限:
chmod +x OSX.sh
然后再次執(zhí)行:

可以看到成功執(zhí)行了腳本。
5.在Linux上運(yùn)行
直接運(yùn)行也是會(huì)有權(quán)限問(wèn)題的:

同樣使用命令加入執(zhí)行權(quán)限:
chmod +x linux.sh
然后再次執(zhí)行:

可以看到成功執(zhí)行了我們的腳本。
4.容易犯的錯(cuò)誤
看見(jiàn)上面的例子,我都成功執(zhí)行了,其實(shí)我踩了幾個(gè)坑,花了我不少時(shí)間來(lái)解決。
1.sh腳本一定要指定命令解析器
也就是這句話,放在sh腳本開(kāi)頭
#!/bin/bash
2.不管是windows linux osx 腳本編碼必須為 ANSI
不然程序執(zhí)行的時(shí)候,讀取字符會(huì)出錯(cuò),造成執(zhí)行異常。
五.寫(xiě)在最后
希望本文能給大家?guī)?lái)幫助,如有問(wèn)題歡迎和我討論。
本文所用代碼地址:https://github.com/stulzq/BlogDemos/tree/master/DotnetCmd
好了,以上就是這篇文章的全部?jī)?nèi)容了,希望本文的內(nèi)容對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,如果有疑問(wèn)大家可以留言交流,謝謝大家對(duì)腳本之家的支持。
相關(guān)文章
GridView導(dǎo)出Excel實(shí)現(xiàn)原理與代碼
使用GridView來(lái)展示數(shù)據(jù)庫(kù)表,幾乎沒(méi)對(duì)GridView的格式做什么設(shè)定,從配置文件中加載SQL,跑出數(shù)據(jù)就直接綁定到GridView,接下來(lái)介紹導(dǎo)出Excel的功能感興趣的朋友可以參考下2013-01-01
動(dòng)態(tài)組合SQL語(yǔ)句方式實(shí)現(xiàn)批量更新的實(shí)例
動(dòng)態(tài)組合SQL語(yǔ)句方式實(shí)現(xiàn)批量更新的實(shí)例,需要的朋友可以參考一下2013-03-03
.Net8.0 WebApi發(fā)布到IIS詳細(xì)步驟
本文主要介紹了.Net8.0 WebApi發(fā)布到IIS詳細(xì)步驟, 文中通過(guò)圖文介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來(lái)一起學(xué)習(xí)學(xué)習(xí)吧2024-05-05
asp.net中的check與uncheck關(guān)鍵字用法解析
這篇文章主要介紹了asp.net中的check與uncheck關(guān)鍵字用法,以實(shí)例形式較為詳細(xì)的分析了check與uncheck關(guān)鍵字的各種常見(jiàn)用法與使用時(shí)的注意事項(xiàng),非常具有實(shí)用價(jià)值,需要的朋友可以參考下2014-10-10
.net?core利用PdfSharpCore操作PDF實(shí)例教程
操作pdf是我們?nèi)粘i_(kāi)發(fā)中經(jīng)常遇到的功能,下面這篇文章主要給大家介紹了關(guān)于.net?core利用PdfSharpCore操作PDF實(shí)例的相關(guān)資料,文中通過(guò)示例代碼介紹的非常詳細(xì),需要的朋友可以參考下2022-12-12
asp.net利用存儲(chǔ)過(guò)程和div+css實(shí)現(xiàn)分頁(yè)(類似于博客園首頁(yè)分頁(yè))
怎么用aspnetpager.dll這個(gè)插件對(duì)服務(wù)器控件進(jìn)行分頁(yè),今天與我大家分享一下asp.net利用存儲(chǔ)過(guò)程和div+css實(shí)現(xiàn)分頁(yè)(類似于博客園首頁(yè)分頁(yè))2012-01-01
asp.net開(kāi)發(fā)微信公眾平臺(tái)之驗(yàn)證消息的真實(shí)性
這篇文章主要介紹了asp.net開(kāi)發(fā)微信公眾平臺(tái)之驗(yàn)證消息的真實(shí)性的相關(guān)資料,需要的朋友可以參考下2015-06-06
密碼綁定至密碼文本框中(TextMode設(shè)為Password)
一般情況之下TextBox的TextMode設(shè)為Password話,我們想在后臺(tái)(.cs)綁定一個(gè)值至此文本框,是無(wú)法實(shí)現(xiàn)的,如果一定要綁定值的話,該如何實(shí)現(xiàn)呢?,本文將告訴你實(shí)現(xiàn)方法,感興趣的朋友可以參考下2013-01-01
asp.net中使用DatagridView的增刪改方法具體實(shí)現(xiàn)
asp.net中使用DatagridView的增刪改方法具體實(shí)現(xiàn),需要的朋友可以參考一下2013-06-06

