循环是控制流中的重要部分,允许在条件满足的情况下重复执行脚本代码块。
简单循环语句while
当简单while循环中的条件表达式成立时,将重复的执行脚本块,其一般格式如下:
while (<condition>) { <action block> }
下例等待notepad.exe进程退出:
PS C:\> while (Get-Process notepad -ErrorAction SilentlyContinue){ >> Write-Host "Waiting for notepad to exit" >> sleep 1 >> } >> Waiting for notepad to exit Waiting for notepad to exit Waiting for notepad to exit
Get-Process notepad -ErrorAction SilentlyContinue语句是反复执行的,并会被转换为布尔类型的值。如果未发现进程,Get-Process将会抛出一个异常,所以传递-ErrorAction SilentlyContinue参数执行容错处理。如果未发现进程仅仅返回一个$null值,则该值会被转换为$false并退出循环。为了不让CPU总是执行无谓。循环而消耗资源,在每个循环过程中调用了sleep命令,在每次循环过程中执行一秒钟的任务后挂起。
如果条件表达式初始化为$false,while循环体将永远不会被执行。为了让循环体至少执行一次,可以使用do-while形式,如:
PS C:\> $i=5 PS C:\> do{ >> Write-Host 'incermenting $i' >> $i++ >> }while($i -le 1) >> incermenting $i
在使用do-while语句时,无论条件成立与否,循环体总是要被执行一次。
该语句确定条件使循环重复执行,直到条件成立,如:
PS C:\> $i=5 PS C:\> do{ >> Write-Host 'incermenting $i' >> $i++ >> }while($i -le 1) >> incermenting $i PS C:\> $i=0; PS C:\> do{ >> Write-Host "`$i=$i" >> $i++ >> }until ($i -ge 3) >> $i=0 $i=1 $i=2
下例中的do-while和do-until循环仅条件不同:
PS C:\> $i=5 PS C:\> do{ >> Write-Host 'incermenting $i' >> $i++ >> }while($i -le 1) >> incermenting $i PS C:\> $i=0; PS C:\> do{ >> Write-Host "`$i=$i" >> $i++ >> }while (-not($i -ge 3)) >> $i=0 $i=1 $i=2
循环和计数器
一般循环包括初始化一个变量作为计数器,并且在每个循环体中修改该计数器,直到满足退出条件。这种形式的循环出即for…loop结构,其一般格式如下:
for(<initializer>;<exit condition>;<step action>) { <action> }
这种循环通过初始化计数器,每次循环的过程中递增或者递减该计数器,直到计数器达到退出要求。下例使用for循环重写前一节的while循环:
PS C:\> for($i=0;$i -lt 3;$i++){ >> Write-Host "`$i=$i" >> } >> $i=0 $i=1 $i=2
for循环比while更为紧凑,可以将其作为while的超集。初始化和步进值对于for循环为可选,如果忽略这些参数,for循环的作用与while类似,如:
PS C:\> $i=0; PS C:\> for(;$i -lt 3;){ >> Write-Host "`$i=$i" >> $i++ >> } >> $i=0 $i=1 $i=2
注意,如果在for循环的条件中省略计数器的初始化和步进表达式,则必须在括号中添加循环退出条件。
遍历集合的循环语句for each Loop
很多情况下需要遍历集合,以操作每个成员,下例使用for循环来达到这个目的:
PS C:\>$items=2,3,4 PS C:\>for($i=0;$i –lt $items.Length;$i++){ >>$item=$items[$i] >>Write-Host $item >>} >> 2 3 4
其中$i变量包含当前项的索引值,$i –lt $items.Length是退出条件。递增语句作为循环的步进值,$item变量使用当前项初始化。PowerShell提供了更为便利的foreach循环,其一般格式如下:
foreach($item in $collection) { <action> }
注意foreach需要提供包含当前项的变量名及要遍历的集合,即索引的初始化、退出条件,以及索引递增已经隐藏到其中。下例使用foreach优化前面的实例:
PS C:\>$items=2,3,4 PS C:\>foreach ($item in $items){ >> Write-Host $item >>} >> 2 3 4
foreach是PowerShell的保留字,同时也是ForEach-Object的别名。PowerShell的解释引擎是会根据语境检测出foreach是作为循环或者ForEach-Object创建管道对象。
控制循环执行语句break和continue
并不是所有的循环都需要严格的退出条件,如果要检测错误或者只是想优化程序,可能希望脚本循环强制退出。强制退出循环使用break语句,下例在当前目录中获取第1个有.log后缀的文件后退出:
PS C:\>foreach ($file in dir){ >>if($file.Name –like "*.log"){ >>Write-Host $fiile.Name >>break >> } >>} >> test.log
如果反复遍历一个集合并操作其中的大多数对象,可以使用continue语句。break所在的程序段的条件满足的情况下将会退出整个循环,而continue语句块的条件成立时将会跳过当前循环,继续下一个循环。下例说明如何使用continue语句在遍历集合的过程中跳过偶数输出所有的奇数:
PS C:\>foreach ($item in 1..5){ >> if ($item %2 –eq 0){ >> continue >> } >>Write-Host $item >>} 1 3 5
在上例中使用取模(%)运算符来判断一个数是奇数还是偶数,偶数除以2余数为零,即模2。
break和continue可以被赋予一个使其退出或者转向循环的其他迭代的循环标记,对嵌套循环非常有用。下例为针对两个嵌套的foreach循环:
PS C:\>foreach ($outerItem in 1..3){ >> Write-Host "OuterItem:$outerItem" >> foreach($innerItem in 1..3){ >> Write-Host "InnerItem:$innerItem" >> break; >> } >>Write-Host $item >>} >> OuterItem:1 InnerItem:1 OuterItem:2 InnerItem:1 OuterItem:3 InnerItem:1
内部循环在外部循环反复执行过程中只执行一遍,这是因为break语句在每次执行第1个Write-Host语句后终止循环。如果要终止外部循环,而不是内部循环,则可以在外部循环中增加break语句;
PS C:\>:OuterLoop foreach ($outerItem in 1..3){ >> Write-Host "OuterItem:$outerItem" >> foreach($innerItem in 1..3){ >> Write-Host "InnerItem:$innerItem" >> break OuterLoop; >> } >>Write-Host $item >>} >> OuterItem:1 InnerItem:1
这样内外两层循环均只执行一次,内部的break语句终止外部的循环,有效地终止了循环:
PS C:\>:OuterLoop foreach ($outerItem in 1..3){ >> Write-Host "OuterItem:$outerItem" >> foreach($innerItem in 1..3){ >> Write-Host "InnerItem:$innerItem" >> break OuterLoop; >> } >>Write-Host $item >>} >> OuterItem:1 InnerItem:1 OuterItem:2 InnerItem:1 OuterItem:3 InnerItem:1
执行结果和本节第1个例子相同,因为continue在终止内部循环的同时开始执行外部循环。
总 结
如果说算法是程序的灵魂,那么控制流就是程序运行的骨架。控制流直接决定了程序运行路径,控制流的内容将会贯穿整个PowerShell学习的全过程,本文主要讲解了循环语句,包括while,for each loop,break和continue,掌握了这部分内容之后读者就可以写出在日常工作中用到该功能的命令。
作者: 付海军
版权:本文版权归作者所有
转载:欢迎转载,为了保存作者的创作热情,请按要求【转载】,谢谢
要求:未经作者同意,必须保留此段声明;必须在文章中给出原文连接;否则必究法律责任
个人网站: http://txj.shell.tor.hu/