引子
公司在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学习笔记》的想法。
感谢Tobias Weltner博士,以及他那本免费的《Master Powershell》!
从CMD SHELL到Powershell
看了《Master Powershell》一遍之后,我觉得学习Powershell是正确的。
CMD SHELL(以下简称CMD)来源于DOS时代的批处理脚本,它最初的设计就是为着顺序批处理来的。在Windows 2000和Windows XP时代,DOS批处理正式升级为CMD SHELL,在语法和功能上做了一些扩展;脚本文件开始支持.CMD扩展名,并兼容之前的.BAT扩展名;其名称也由“DOS窗口”改为“命令提示符”。CMD SHELL虽然可以完成很多比较复杂的任务,但却非常考验脚本开发者大脑的堆栈大小。
CMD的确适合写一些简单的SHELL程序,而Powershell却包含了写一个复杂的脚本程序所需要的各种支持,包括语法和函数库——巨大的.NET函数库。
1. 参数处理,Powershell方便不只一点点
CMD中处理参数,通常是按顺序处理%1-%9,参数比较多还需要通过SHIFT命令来对参数进行移位。如果想处理位置不定的switch参数,或者处理命名参数,那就分析参数这部分脚本都能把人搞搅晕。而Powershell原生就支持参数数组、命名参数和switch参数。比如
- # 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若干条件分支以及若干临时的环境变量。
2. Powershell,Powered Variable
CMD中的变量,其实都是环境变量,而且其值一定是字符串。而Powershell中有真正意义的变量,并且这些变量可以是字符串类型、数值类型、日期类型……甚至任意对象类型,只要是.NET库中支持的对象。不错,Powershell是一个面向对象的脚本。很酷,是么?
CMD中如果需要列表怎么办——用分号分隔的字符串值;那如果需要哈希表呢——用分号分隔的带等号的字符串值……是的,CMD可以做到,只是处理起来麻烦一点而已。当然,在Powershell中不需要这么麻烦,Powershell支持数组类型的变量和哈希表类型的变量,就像——嗯,像什么呢?有点像PHP,也有点像Javascript。
- # 定义一个数组
- $a = 1,2,3
- # 也可以这样定义
- $a = @(1,2,3)
- # 或者定义一个空数组
- $a = @()
- # 再定义两个哈希表
- $m1 = ${ key1="value1";key2=1234 }
- $emptymap = ${}
3. 丰富的表达式
在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)
4. 字符串处理的天堂
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)
5. 流程控制,伟大的飞跃
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
6. 函数和函数库
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
7. 其它
Powershell的好处远不止上面所说的那些,难怪Microsoft这么强烈的推荐使用Powershell代替CMD。甚至有人认为Powershell将成为Windows脚本的霸主。它的确比CMD强大了不止一点点,就是相对于WSH来说,它的便捷性和强大的.NET支持也是WSH所不能比拟的——压根就不是一个数量级的东西。
本文转自边城__ 51CTO博客,原文链接:http://blog.51cto.com/jamesfancy/678945,如需转载请自行联系原作者