▲F#和PowerShell模塊
作為可能是人類世界最強(qiáng)大的Shell,PowerShell最大的特點(diǎn)是能夠直接在命令間傳遞.NET對(duì)象,而支持這種能力的命令被稱作cmdlet。自己編寫PowerShell模塊,就能給PowerShell擴(kuò)展更多的cmdlet。
為何要寫本文
通常來講,PowerShell模塊有兩種:腳本模塊和二進(jìn)制模塊。顧名思義,腳本模塊基本上就是一組PowerShell腳本,而二進(jìn)制模塊,實(shí)質(zhì)上是一個(gè).NET類庫。微軟對(duì)于二進(jìn)制模塊的官方文檔中,只提供了C#的范例;但鑒于F#和C#幾乎是同等強(qiáng)大的,我在想,使用F#也能編寫出可以工作的PowerShell模塊。經(jīng)過一小段時(shí)間的研究和整理,我決定將可行的方案分享給之家的朋友們。
任務(wù)目標(biāo)
使用F#編寫一個(gè)PowerShell模塊,提供一個(gè)名為Get-Sum的cmdlet,完成對(duì)一個(gè)整數(shù)數(shù)組求和的功能。至于為什么選擇“求和”,是因?yàn)檫f歸求和函數(shù)通常是F#這類函數(shù)式編程語言第一課必學(xué)的例子,這種遞歸的思想也算是函數(shù)式語言的特色之一。
正式開始
1、建立項(xiàng)目
開始上手操作之前,確保你安裝了.NET Core SDK,并經(jīng)過適當(dāng)配置,可以在任意位置使用“dotnet”命令。
打開PowerShell,在你通常保存項(xiàng)目代碼的地方創(chuàng)建一個(gè)目錄,作為整個(gè)項(xiàng)目的根。在這個(gè)目錄下,使用dotnet new命令創(chuàng)建一個(gè)F#的類庫項(xiàng)目和一個(gè)解決方案文件,并將項(xiàng)目添加進(jìn)解決方案中。
如此,我們便建立了解決方案fsharp-module和F#類庫工程testmodule。
2、添加用于編寫/生成PowerShell模塊的組裝件
使用dotnet add package為工程testmodule添加名為PowerShellStandard.Library的組裝件,這個(gè)組裝件由微軟提供,并將為工程提供System.Management.Automation名稱空間和必要的類型。
如此,我們建立的F#類庫已經(jīng)可以用于編寫PowerShell模塊了。
3、編寫代碼
使用自己喜愛的代碼編輯器修改testmodule\Library.fs,代碼內(nèi)容如下,我將在代碼的下方解釋一些要點(diǎn)。
注0:代碼中的向右的箭頭是->兩個(gè)字符,向右的三角形是|>兩個(gè)字符。這種連體字由著名字體FiraCode提供?;疑⑨屖荲SCode相關(guān)插件自動(dòng)生成的;
注1:此名稱空間包含了編寫PowerShell模塊必須的類型;
注2:任何作cmdlet存在的類型必須加上Cmdlet屬性(Attribute)。任何cmdlet的名稱都由兩部分組成:動(dòng)詞(Verb)和名詞(Noun),最終形成“Verb-Noun”形式的名稱。在這里,我們定義VerbName為Get,NounName為Sum,即得到最終的cmdlet名稱Get-Sum。需要注意的是,Verb的選擇需要遵守微軟的規(guī)范。如果你執(zhí)意要使用奇怪的Verb,構(gòu)建代碼時(shí)和導(dǎo)入模塊時(shí)就會(huì)產(chǎn)生警告。任何cmdlet類都必須繼承于PSCmdlet類;
注3:一個(gè)很經(jīng)典的遞歸求和函數(shù)。我知道這功能可以干脆使用Array.sum方法來實(shí)現(xiàn),但作為函數(shù)式語言的標(biāo)志性操作之一,展示出來可以展現(xiàn)函數(shù)式語言和命令式語言的某種區(qū)別;
注4:Parameter屬性(Attribute)標(biāo)記的InputArray屬性(Property)用來接收傳遞過來的參數(shù)對(duì)象。可以在Parameter屬性(Attribute)中指定關(guān)于這個(gè)參數(shù)的更多細(xì)節(jié),比如參數(shù)的位置、能否從管道中接收等等;
注5:重寫基類(部分Java程序員會(huì)稱作父類,其實(shí)都一樣)的EndProcessing方法(命令處理完成后)執(zhí)行求和操作并輸出結(jié)果。類似的可供重寫的虛函數(shù)還有BeginProcessing、ProcessRecord和StopProcessing,它們分別表示命令開始執(zhí)行之前、命令執(zhí)行的主體和命令中斷時(shí)的過程。原則上求和應(yīng)放在ProcessRecord中執(zhí)行,但由于我們命令的功能很簡單,干脆直接在EndProcessing里直接輸出求和的結(jié)果。
4、編譯模塊并測試
使用dotnet publish命令發(fā)布這個(gè)類庫。之所以使用publish而不是build,是因?yàn)镕#程序還依賴另一個(gè)組裝件:FSharp.Core來運(yùn)行,而build默認(rèn)不包含該組裝件,該模塊將不能被導(dǎo)入PowerShell中。
發(fā)布完成后,使用Import-Module命令導(dǎo)入我們編寫的模塊,并測試功能。
其實(shí),別看這個(gè)cmdlet輸出的是看似文本的5050,其實(shí)它輸出的是一個(gè)System.Int32,你可以使用GetType()函數(shù)來證明這一點(diǎn):
也正是這種在管道中傳遞對(duì)象的能力,使PowerShell比別的一些Shell擁有更高的潛力。
廣告聲明:文內(nèi)含有的對(duì)外跳轉(zhuǎn)鏈接(包括不限于超鏈接、二維碼、口令等形式),用于傳遞更多信息,節(jié)省甄選時(shí)間,結(jié)果僅供參考,IT之家所有文章均包含本聲明。