转自http://itecn.net/blogs/ghjconan/archive/2008/03/03/windows-powershell-27-switch.aspx
当脚本专家参加去年11月份的TechED峰会之时,我们抽空离开了自己的展位去聆听Windows PowerShell架构师Jeffrey Snover关于PowerShell的演讲。在他的演讲中,Jeffrey Snover提到一点,PowerShell中最酷最有用的特性之一是Switch语句。不必说,这让脚本专家感到一丝惊讶:在PowerShell所包含的所有特性中最酷最有用的特性之一是switch语句?!?我们发现这有点难以理解。
但是你对switch语句又了解多少呢?Jeffrey很有可能是正确的。
基础的Switch语句
Switch语句与VBScript的Select Case语句很相似:它使你能编写一个从一系列选项中进行选择的脚本,而不是一系列的if语句。例如,考虑以下脚本:
$a = 5 switch ($a) { 1 {"The color is red."} 2 {"The color is blue."} 3 {"The color is green."} 4 {"The color is yellow."} 5 {"The color is orange."} 6 {"The color is purple."} 7 {"The color is pink."} 8 {"The color is brown."} default {"The color could not be determined."} } |
在这个脚本中我们从将5赋值给名为$a的变量开始。随后我们又建立了一个Switch语句块来访问$a的值并基于该值显示相应的结果。这就是下面这行代码的作用:
switch ($a) |
如你所见,我们所做的是插入Switch关键字并在其后跟上将被检测的值(噢,在PowerShell中作为case的替代,被检测值必须被括号括起来)。
接下来的一系列语句都包含在一个脚本块中。(也就是说,都包含在花括号中。)脚本块中的代码是让脚本基于被检测值显示相应的结果。例如,如果$a等于1,那我们将要回显一条消息说明被检测值的颜色是红色。因此,我们使用了以下代码,而具体要回显的信息也包含在花括号中:
1 {"The color is red."} |
现在知道它如何工作了吧?你当然也注意到了,在脚本块的结束部分,我们指定了如果没有一句Case处理语句为真时将要回显的信息,(和你在VBScript中使用Case Else一样)。为了达到这个目的,我们只需将想要显示的结果与default条件关联:
default {"The color could not be determined."} |
通过以上说明,你就明白了Windows PowerShell switch语句的使用方法。当我们运行先前的脚本时,屏幕上将会回显以下信息:
The color is orange. |
在Switch语句中使用通配符
现在,我们知道你在想什么:这很正确,但这不太酷。说的好。但是假设我们告诉你在switch语句中可以使用通配符,这将会改变你认为switch语句不太酷的观点么?
例如,考虑下这个脚本,有人将$a的值设为d14151。我们假设这里的d14151是由字母和数字组合而成的字符串,d意味着该字符串代表黄色。那么我们如何回显被检测的字符串所代表的颜色是黄色,特别是如果我们有一组数字以字母d开头(d14151,d14152,d14153等等)?好的,下面就是解决这个问题的一个方法:
$a = "d14151"
switch -wildcard ($a) { "a*" {"The color is red."} "b*" {"The color is blue."} "c*" {"The color is green."} "d*" {"The color is yellow."} "e*" {"The color is orange."} "f*" {"The color is purple."} "g*" {"The color is pink."} "h*" {"The color is brown."} default {"The color could not be determined."} } |
注意我们在这里所做的。首先,我们添加了-wildcard参数;这告诉switch语句当我们访问$a时我们将使用通配符。其次,注意我们在条件语句中使用了星号(一个代表“任意”的通配符):
"a*" {"The color is red."} |
这行代码的意义是:“如果$a的值以字母a开头,我们也不关心其后所跟随的字母,可以是任意字符,然后回显被检测值所代表的颜色是红色。”换句话说,如果$a等于a14151,或者$a等于a7777777777,或者$a等于apple,或者$a等于任意以字母a打头的字符串,那么被检测值所代表的颜色是红色。
这真的可行么?我们可以就此和你打赌;我们的字符串以字母d作为打头字母,而我们的脚本将会正确回显它所代表的颜色是黄色:
The color is yellow |
顺便说一句,你能在字符串的任意位置放置通配符。当$a中最后一个字母是d时,想要回显相应的语句?那么使用以下命令,即字母d跟随在星号后:
"*d" {"The color is yellow."} |
下面是另外一个有趣的通配符。假设,字符串中的首字母与颜色无关。(例如,首字母也许是代表该部件的产地。)而字符串的最后五位字符才决定是什么颜色。那我们怎么从给定的字符串中区分出颜色信息呢?当然像这样:
$a = "d14151"
switch -wildcard ($a) { "?14150" {"The color is red."} "?14151" {"The color is blue."} "?14152" {"The color is green."} "?14153" {"The color is yellow."} "?14154" {"The color is orange."} "?14155" {"The color is purple."} "?14156" {"The color is pink."} "?14157" {"The color is brown."} default {"The color could not be determined."} } |
这次我们通过使用问号后跟随五位数字来配置我们的条件语句。这是一个标准的通配符约定:问号代表“任一字符”。换句话说,"?14150" {"The color is red."}表示:“如果$a以任一字符打头,其后跟随14150那么该字符串所代表的颜色是红色。”想知道具体怎么执行?如果$a等于d14151,那么我们的脚本应当返回“the color is blue”。让我们看下结果:
The color is blue. |
你知道,当我们越来越多的使用switch语句时,我们就越来越相信它真的很酷。
在Switch语句中使用正则表达式
通配符很棒,但是它们有它们自身的限制;作为对比,很少有正则表达式不能完成的事。例如,假设有一个范围内的字母是表示一种特定的颜色;也就是说,假设任何以字母a,b,c,d开头的字符串所代表的颜色是红色。你能使用通配符来辨别颜色类型么?实话对你说,我们不敢保证。但是我们知道你可以使用正则表达式来决定颜色类型:
$a = "r14151"
switch -regex ($a) { "[a-d]" {"The color is red."} "[e-g]" {"The color is blue."} "[h-k]" {"The color is green."} "[l-o]" {"The color is yellow."} "[p-s]" {"The color is orange."} "[t-v]" {"The color is purple."} "[w-y]" {"The color is pink."} " default {"The color could not be determined."} } |
那么这个脚本同我们的通配符脚本的区别是什么?好的,首先,我们使用-regex参数替代-wildcard参数;如同你可能猜测的,该参数告诉switch语句我们将在条件语句中使用正则表达式。然后我们在条件语句中使用了正则表达式。假设我们想要从a,b,c或d中选择出任意一个。在正则表达式中,我们可以通过指定一个字符范围[a-d]来完成这件事。猜下我们的第一个条件语句看上去怎么样?
"[a-d]" {"The color is red."} |
很漂亮吧?如果$a被设置为r14151(现在的确是),那么当我们运行以下脚本的时候将得到以下信息:
The color is orange. |
让我们使用正则表达式来展示switch语句的另一项特性。让我们假设颜色由字符串的数字个数来表示。换句话说,你能简单的通过统计$a的数字个数来判断颜色类型。一种处理这个问题的方法是(不是最好的方法,提醒下你,但是该方法能满足我们的根本需要):
$a = "14151"
switch -regex ($a) { "\d{8}" {"The color is red."} "\d{7}" {"The color is blue."} "\d{6}" {"The color is green."} "\d{5}" {"The color is yellow."} "\d{4}" {"The color is orange."} "\d{3}" {"The color is purple."} "\d{2}" {"The color is pink."} "\d{1}" {"The color is brown."} default {"The color could not be determined."} } |
如你所见(假设你对正则表达式有基本的认识),在第一个条件处是检查$a中是否包含8个连续数字(\d{8})。如果包含,那么脚本将回显“The color is red.” 在第二个条件处是检查$a中是否包含7个连续数字,如此类推。因为$a包含了五位连续数字你也许期待脚本将告诉我们“the color is yellow”。尽管不幸的是,,它告诉我们以下信息:
The color is yellow. The color is orange. The color is purple. The color is pink. The color is brown. |
很可惜。
那么是哪里出错了呢?在VBScript Select Case语句中一旦条件成立那么脚本就会退出Select Case语句,它不再继续检查其它所有条件。但这在PowerShell中不是必然正确的。PowerShell检查$a是否包含五个连续数字,因为它完成了这个检查,所以它回显“the color is yellow”这个消息,这很棒。
但是PowerShell不像VBScript,它不在此处停止下来。相反的它继续检验下一个条件。因为$a也确实包含了四个连续数字,所以脚本也回显了“the color is orange”。PowerShell也不在此处停止。事实上,它忠实地检查了switch语句中的每一个条件。
再次感到遗憾。
在很多时候这个功能是很不错。尤其是像组合数字这样一个值包含能满足多个条件的信息的情况(它包含了五个连续数字那么它所代表的颜色是红色,以字母d开头则意味着它的制造商在Des Moines,等等)。在其它时候,比如这次,我们真心希望PowerShell在找到第一个符合的条件后就能退出switch语句。但是我们如何实现呢?
事实上,这很简单:只需在脚本块中的每一个条件后添加break语句:
$a = "14151" switch -regex ($a) { "\d{8}" {"The color is red.”; break} "\d{7}" {"The color is blue.”; break} "\d{6}" {"The color is green.”; break} "\d{5}" {"The color is yellow.”; break} "\d{4}" {"The color is orange.”; break} "\d{3}" {"The color is purple.”; break} "\d{2}" {"The color is pink.”; break} "\d{1}" {"The color is brown.”; break} default {"The color could not be determined."} } |
|
这次,当PowerShell找到第一个符合的条件后($a包含五位数字)就会退出。
在Switch语句中使用数组
让我们再向你展示另一个Switch语句的使用方法,仅仅因为喜欢它。令人感到惊异的是,switch语句实际上能检验数组。换句话说,假设我们拥有以下脚本:
$a = 21, 38, 6 switch ($a) { 1 {"The color is red."} 2 {"The color is blue."} 3 {"The color is green."} 4 {"The color is yellow."} 5 {"The color is orange."} 6 {"The color is purple."} 7 {"The color is pink."} 8 {"The color is brown."} }
|
当我们运行这个脚本时,PowerShell会检查数组$a中的所有对象是否匹配指定的条件。例如,第一个条件是:“如果$a等于1那么颜色是红色。”PowerShell将会检查$a中的三个值(21,38和6)来判断它们中的任意一个是否满足标准。如果找到一个匹配项目,那么脚本将会回显合适的消息。换句话说:
The color is purple. |
Jeffrey,你是对的:switch语句的确很酷。
下周见。
英文原文
http://www.microsoft.com/technet/scriptcenter/resources/pstips/jan08/pstip0111.mspx