公司在Windows環境下進行開發,因此在寫自動構建的時候,天然而然地想到了CMD SHELL。原本考慮過使用Windows Script Host腳本(WSF、JS或VBS)來寫,但要在WSH腳本里調用VS的批處理來設置環境很困難。隨着項目結構變得複雜,CMD SHELL寫的構建腳本也開始變得複雜,這個時候就感到CMD SHELL有點吃力了,因而想到了Powershell。正則表達式
在這以前對Powershell其實有過一些瞭解,知道它是一個比CMD SHELL更適合寫腳本程序的東西,跟.NET有着莫大的關係。不過以前的瞭解也僅此而已,因此仍是須要先學習一下。經過Google找到了Tobias Weltner博士寫的《Master Powershell》(http://powershell.com/cs/blogs/ebook/),花了半天揀想了解的部分通看了一遍,因而有了寫下《Powershell學習筆記》的想法。shell
感謝Tobias Weltner博士,以及他那本免費的《Master Powershell》!數組
看了《Master Powershell》一遍以後,我以爲學習Powershell是正確的。ide
CMD SHELL(如下簡稱CMD)來源於DOS時代的批處理腳本,它最初的設計就是爲着順序批處理來的。在Windows 2000和Windows XP時代,DOS批處理正式升級爲CMD SHELL,在語法和功能上作了一些擴展;腳本文件開始支持.CMD擴展名,併兼容以前的.BAT擴展名;其名稱也由「DOS窗口」改成「命令提示符」。CMD SHELL雖然能夠完成不少比較複雜的任務,但卻很是考驗腳本開發者大腦的堆棧大小。函數
CMD的確適合寫一些簡單的SHELL程序,而Powershell卻包含了寫一個複雜的腳本程序所須要的各類支持,包括語法和函數庫——巨大的.NET函數庫。學習
CMD中處理參數,一般是按順序處理%1-%9,參數比較多還須要經過SHIFT命令來對參數進行移位。若是想處理位置不定的switch參數,或者處理命名參數,那就分析參數這部分腳本都能把人搞攪暈。而Powershell原生就支持參數數組、命名參數和switch參數。好比spa
- # test.ps1
- # 在腳本中定義命名參數和switch參數
- param($name, [switch] $isMale)
- # 若是 .\test.ps1 -name "James Fancy" -ismale
- # $name的值爲James Fancy
- # $isMale的值爲True
- # 若是缺省-ismale參數,$isMale的值爲False
- # 若是 .\test.ps1 -name -ismale
- # 會直接報告錯誤,由於-name須要附加的參數
可見Powershell已經將參數處理部分進行了很好的封閉。若是要用CMD來寫,那就須要GOTO、SHIFT若干條件分支以及若干臨時的環境變量。設計
CMD中的變量,其實都是環境變量,並且其值必定是字符串。而Powershell中有真正意義的變量,而且這些變量能夠是字符串類型、數值類型、日期類型……甚至任意對象類型,只要是.NET庫中支持的對象。不錯,Powershell是一個面向對象的腳本。很酷,是麼?orm
CMD中若是須要列表怎麼辦——用分號分隔的字符串值;那若是須要哈希表呢——用分號分隔的帶等號的字符串值……是的,CMD能夠作到,只是處理起來麻煩一點而已。固然,在Powershell中不須要這麼麻煩,Powershell支持數組類型的變量和哈希表類型的變量,就像——嗯,像什麼呢?有點像PHP,也有點像Javascript。xml
- # 定義一個數組
- $a = 1,2,3
- # 也能夠這樣定義
- $a = @(1,2,3)
- # 或者定義一個空數組
- $a = @()
- # 再定義兩個哈希表
- $m1 = ${ key1="value1";key2=1234 }
- $emptymap = ${}
在CMD中若是想計算四則運算,須要用到SET /A命令,能夠進行常見的各類算術運算。Powershell固然不輸於CMD。Powershell中能夠進行各類各樣的運算,並且徹底不須要經過命令來進行。
固然Powershell能作的不只是這樣。好比獲取日期,CMD下須要獲取日期固然是用DATE命令,若是要乾淨一點的日期,用DATE /T,不過輸出的日期格式嘛……固然就看在Windows裏怎麼設置的啦。而在Powershell裏,日期是一個對象,格式嘛,固然能夠想什麼樣就什麼樣……
- # 按兩種格式輸出日期
- (get-date).toString("yyyy-MM-dd HH:mm:ss")
- # 輸出 2011-10-04 09:54:47
- (get-date).toString("yyyy年M月d日")
- # 輸出 2011年10月4日
對了,還有條件表達式,Powershell是經過-eq、-ne、-lt、-gt等運算符來進行比較,還能夠經過-and、-or等運算符來表達組合條件……差點忘了-not,固然它還能夠簡寫成「!」。
- # 下面表達式返回True
- (1 -lt 2) -and (3 -eq 03)
CMD中想要處理字符串,那簡直就是惡夢!雖然SET和FOR命令外加GOTO或者CALL命令能夠對字符串進行一些簡單的處理,可是處理起來那是真的太太太複雜了。如今來到Powershell,天堂啊!字符串能夠很是方便地重複、拼接、拆分、各類比較,甚至匹配正則表達式,由於這些都是.NET中的String對象所具備的能力。
- # 輸出20個減號
- "-" * 20
- # 拼接爲Powershell
- "Powerh" + "shell"
- # 匹配,如下均返回True
- "powershell" -eq "POWERSHELL"
- "powershell" -like "power*"
- "powershell" -match "shell"
- "powershell".startsWith("p")
- # 區分大小寫的比較和匹配,如下均返回False
- "powershell" -ceq "POWERSHELL"
- "powershell" -clike "P*"
- "powershell".startsWith("P")
差點忘了偉大的String.Format,格式化字符串,直接看療效:
- # 輸出00EA
- "{0:X4}" -f 234
- # 上述語句等效於
- [string]::format("{0:X4}", 234)
CMD固然提供了控制流程控制,由於它提供了IF命令和FOR命令。IF命令很簡單,它的方便性徹底取決於條件表達式是否方便,從這一點一說,CMD的IF語句很好很強大。雖然沒有SWITCH語句是個遺憾,但至少不少個IF語句是徹底撐得起場面的。但話說回來,要FOR語句撐起循環的一片天,還真有點吃力,因此才常常會有經過GOTO語句來模擬循環的狀況發生。
來到Powershell中,提及流程控制,那簡直就是一個飛躍。
從條件分支控制來講,if和switch固然一個都不能少,而switch,更是很是的強大。switch精確匹配數值,這是常規功能;它還能匹配條件表達式,這彷佛有點讓人驚喜了;它還能夠按區分大小寫和不區分大小寫兩種方式匹配字符串;不止這些,它還能夠按通配符進行匹配;都到這一步了,那按正則表達式匹配也少不掉啦!
提及Powershell的循環,那就更是多樣了,光Foreach都有兩種,一種是Foreach關鍵字,用於數組地遍歷;另外一種是Foreach-Object命令,用於遍歷管道輸出的多個對象。很巧……也許是Microsoft故意的,Foreach-Object有個別名,就叫Foreach。另外,For語句固然不會少,還有常見的Do...While和While {}兩種循環。這些都很覺,最神奇的,是Switch語句也能夠用於循環處理數組,而且根據數組中各項的匹配狀況來進行不一樣的處理——就至關因而把內嵌Switch的For/Foreach結構簡化了同樣!來個例子
- $array = 1..5
- switch ($array) {
- {$_ % 2} { "$_ is odd" }
- default { "$_ is even" }
- }
- # 輸出以下
- # 1 is odd
- # 2 is even
- # 3 is odd
- # 4 is even
- # 5 is odd
CMD有函數嗎?沒有。CMD只是經過CALL模擬了函數調用。在腳本內部,「CALL:標籤」和GOTO:EOF能夠模擬函數調用及返回。而在腳本外部,則經過「CALL 腳本.CMD」來實現。因此CMD的函數庫,是一堆.CMD或者.BAT文件。
Powershell固然是支持定義函數的——經過function關鍵字。並且若是把若干函數放在一個.ps1腳本文本中,再經過點號(.)來調用的話,這些函數當即對當前環境可用——也就是說,這個.ps1腳本文件就是函數庫。將相關的函數組織在一個腳本文件中固然會比組織在N個腳本文件中方便得多,也更利於發佈。
固然,關鍵問題在於Powershell支持函數。Powershell的函數也能夠像腳本文件同樣定義參數列表、命名參數和switch參數,並提供極其方便的解析功能。除此以外,Powershell的函數能夠有返回值。不只有,並且很強大,它能夠以數組的的方式返回多個值。就像這樣
- # 定義函數
- function test([string] $a, [string] $b) {
- $a.toUpper();
- $b.toLower();
- }
- # 調用
- $x, $y = test("James", "Fancy")
- "`$x = $x, `$y = $y"
- # 輸出 $x = JAMES, $y = fancy
Powershell的好處遠不止上面所說的那些,難怪Microsoft這麼強烈的推薦使用Powershell代替CMD。甚至有人認爲Powershell將成爲Windows腳本的霸主。它的確比CMD強大了不止一點點,就是相對於WSH來講,它的便捷性和強大的.NET支持也是WSH所不能比擬的——壓根就不是一個數量級的東西。