about_Switch
简短说明
介绍如何使用开关来处理多个 if
语句。
长说明
若要检查脚本或函数中的条件,请使用 if
语句。
if
语句可以检查许多类型的条件,包括变量的值和对象的属性。
若要检查多个条件,请使用 switch
语句。
switch
语句等效于一系列 if
语句,但更简单。
switch
语句列出了每个条件和可选操作。 如果条件获得,则执行该操作。
switch
语句可以使用 $_
和 $switch
自动变量。 有关详细信息,请参阅 about_Automatic_Variables。
语法
基本 switch
语句具有以下格式:
switch (<test-expression>)
{
<result1-to-be-matched> {<action>}
<result2-to-be-matched> {<action>}
}
等效的 if
语句包括:
if (<result1-to-be-matched> -eq (<test-expression>)) {<action>}
if (<result2-to-be-matched> -eq (<test-expression>)) {<action>}
<test-expression>
是在表达式模式下计算以返回值的单个表达式。
<result-to-be-matched>
是一个表达式,其值与输入值进行比较。 表达式包括返回布尔值的文本值(字符串或数字)、变量和 scriptblock。
未识别为数字的任何未标记值都将被视为字符串。
为了避免混淆或意外的字符串转换,应始终为字符串值加引号。 将任何表达式括在括号 ()
中,创建子表达式,以确保表达式的求值正确。
请务必了解 <result-to-be-matched>
值位于比较表达式的左侧。 这意味着 <test-expression>
的结果位于右侧,可以转换为左侧值的类型进行比较。 有关详细信息,请参阅 about_Comparison_Operators
值 default
是为没有其他匹配项时使用的操作保留的。
$_
自动变量包含传递给 switch
语句的表达式的值,可在 <result-to-be-matched>
语句范围内进行计算和使用。
完整的 switch
语句语法如下所示:
switch [-Regex | -Wildcard | -Exact] [-CaseSensitive] (<test-expression>) {
string | number | variable | { <value-scriptblock> }
{ <action-scriptblock> }
default { <action-scriptblock> } # optional
}
、
switch [-Regex | -Wildcard | -Exact] [-CaseSensitive] -File filename {
string | number | variable | { <value-scriptblock> }
{ <action-scriptblock> }
default { <action-scriptblock> } # optional
}
如果不使用参数,switch
的行为与使用 Exact 参数的行为相同。 它针对值执行不区分大小写的匹配。 如果值是一个集合,则每个元素都将按其出现的顺序进行计算。
switch
语句必须至少包含一个条件语句。
当值与任何条件不匹配时,将触发 default
子句。 它等效于 if
语句中的 else
子句。 每个 default
语句中只允许一个 switch
子句。
switch
具有以下参数:
- Wildcard - 指示条件为通配符字符串。 如果 match 子句不是字符串,则忽略参数。 比较不区分大小写。
- 精确 - 指示匹配子句(如果为字符串)必须完全匹配。 如果 match 子句不是字符串,则忽略此参数。 比较不区分大小写。
- CaseSensitive - 执行区分大小写的匹配。 如果匹配子句不是字符串,则忽略此参数。
-
文件 - 从文件(而不是
<test-expression>
)获取输入。 文件一次读取一行,由switch
语句计算。 默认情况下,比较不区分大小写。 File 参数仅支持一个文件。 如果包含多个 File 参数,则仅使用最后一个参数。 有关详细信息,请参阅 文件参数示例。 -
Regex - 执行值与条件的正则表达式匹配。 如果 match 子句不是字符串,则忽略此参数。
比较不区分大小写。
$Matches
自动变量可用于匹配语句块。
注意
指定冲突值(如 Regex 和 Regex)时,指定的最后一个参数优先,并忽略所有冲突参数。 还允许多个参数实例。 但是,仅使用列出的最后一个参数。
简单匹配示例
在以下示例中,switch
语句将测试值 3
与每个条件进行比较。 当测试值与条件匹配时,将执行该操作。
switch (3) {
1 { "It's one." }
2 { "It's two." }
3 { "It's three." }
4 { "It's four." }
}
It's three.
在此示例中,该值与列表中的每个条件进行比较。 以下 switch
语句的值为 3 有两个条件,其中演示了所有条件都经过测试。
switch (3) {
1 { "It's one." }
2 { "It's two." }
3 { "It's three." }
4 { "It's four." }
3 { "Three again." }
}
It's three.
Three again.
若要指示 switch
在匹配后停止比较,请使用 break
语句。
break
语句终止 switch
语句。
switch (3) {
1 { "It's one." }
2 { "It's two." }
3 { "It's three."; break }
4 { "It's four." }
3 { "Three again." }
}
It's three.
如果测试值是一个集合(如数组),则会按其出现的顺序对集合中的每个项进行求值。 以下示例依次计算 4 和 2。
switch (4, 2) {
1 { "It's one." }
2 { "It's two." }
3 { "It's three." }
4 { "It's four." }
3 { "Three again." }
}
It's four.
It's two.
任何 break
语句都应用于该集合,而不是每个值,如以下示例所示。
switch
语句由值为 4 中的条件中的 break
语句终止。
switch (4, 2) {
1 { "It's one."; break }
2 { "It's two." ; break }
3 { "It's three." ; break }
4 { "It's four." ; break }
3 { "Three again." }
}
It's four.
更复杂的匹配示例
在此示例中,该 switch
语句正在测试哈希表中值的类型。 必须使用和表达式返回布尔值以选择要执行的 scriptblock。
$var = @{A = 10; B = 'abc'}
foreach ($key in $var.Keys) {
switch ($var[$key].GetType()) {
{ $_ -eq [int32] } { "$key + 10 = $($var[$key] + 10)" }
{ $_ -eq [string] } { "$key = $($var[$key])" }
}
}
A + 10 = 20
B = abc
在此示例中,不是字符串或数值数据的对象传递给 switch
。
switch
对对象执行字符串强制转换,并计算结果。
$test = @{
Test = 'test'
Test2 = 'test2'
}
$test.ToString()
switch -Exact ($test) {
'System.Collections.Hashtable' { 'Hashtable string coercion' }
'test' { 'Hashtable value' }
}
System.Collections.Hashtable
Hashtable string coercion
在此示例中,没有匹配的大小写,因此没有输出。
switch ("fourteen") {
1 { "It's one."; break }
2 { "It's two."; break }
3 { "It's three."; break }
4 { "It's four."; break }
"fo*" { "That's too many." }
}
通过添加 default
子句,可以在没有其他条件成功时执行操作。
switch ("fourteen") {
1 { "It's one."; break }
2 { "It's two."; break }
3 { "It's three."; break }
4 { "It's four."; break }
"fo*" { "That's too many." }
default { "No matches" }
}
No matches
若要使单词 fourteen
与大小写匹配,必须使用 -Wildcard
或 -Regex
参数。
switch -Wildcard ("fourteen") {
1 { "It's one."; break }
2 { "It's two."; break }
3 { "It's three."; break }
4 { "It's four."; break }
"fo*" { "That's too many." }
}
That's too many.
以下示例使用 -Regex
参数。
$target = 'https://bing.com'
switch -Regex ($target) {
'^ftp\://.*$'
{
"$_ is an ftp address"
break
}
'^\w+@\w+\.com|edu|org$'
{
"$_ is an email address"
break
}
'^(http[s]?)\://.*$'
{
"$_ is a web address that uses $($Matches[1])"
break
}
}
https://bing.com is a web address that uses https
以下示例演示如何将脚本块用作 switch
语句条件。
switch ("Test") {
{ $_ -is [string] } { "Found a string" }
"Test" { "This $_ executes as well" }
}
Found a string
This Test executes as well
以下示例处理包含两个日期值的数组。
<value-scriptblock>
比较每个日期的 Year 属性。
<action-scriptblock>
显示欢迎消息或 2022 年初之前的天数。
switch ((Get-Date 1-Jan-2022), (Get-Date 25-Dec-2021)) {
{ $_.Year -eq 2021 }
{
$days = ((Get-Date 1/1/2022) - $_).Days
"There are $days days until 2022."
}
{ $_.Year -eq 2022 } { 'Welcome to 2022!' }
}
如果值与多个条件匹配,则执行每个条件的操作。 若要更改此行为,请使用 break
或 continue
关键字。
break
关键字停止处理并退出 switch
语句。
continue
关键字停止处理当前值,但将继续处理任何后续值。
以下示例处理一组数字,并显示它们是否奇数或偶数。 使用 continue
关键字跳过负数。 如果遇到非数字,则使用 break
关键字终止执行。
switch (1,4,-1,3,"Hello",2,1) {
{$_ -lt 0} { continue }
{$_ -isnot [int32]} { break }
{$_ % 2} { "$_ is Odd" }
{-not ($_ % 2)} { "$_ is Even" }
}
1 is Odd
4 is Even
3 is Odd
文件参数示例
将 switch
语句与 File 参数结合使用是逐行处理大型文件的有效方法。 PowerShell 将文件的行流式传输到 switch
语句。 每行分别处理。
可以在作语句中使用 break
关键字终止处理,然后再到达文件的末尾。
switch
语句比使用 Get-Content
逐行处理大型文件更有效。
可以将 switch -File
与 -Wildcard
或 -Regex
相结合,实现灵活高效的逐行模式匹配。
以下示例读取 PowerShell-Docs 存储库中的 README.md
。
它输出每行,直到到达以 ##
开头的行。
switch -Regex -File .\README.md {
'^##\s' { break }
default { $_; continue }
}
<filename>
参数解释为通配符表达式,但它必须仅匹配一个文件。 以下示例与上一个示例相同,只不过它在 <filename>
参数中使用通配符。 此示例有效,因为通配符模式仅匹配一个文件。
switch -Regex -File .\README.* {
'^##\s' { break }
default { $_; continue }
}
如果希望将其视为文本,则必须转义字符,这些字符可以解释为通配符。
$file = (New-Item -Path 'Temp:\Foo[0]' -Value Foo -Force).FullName
switch -File $file { Foo { 'Foo' } }
# No files matching '...\Temp\Foo[0]' were found.
$fileEscaped = [WildcardPattern]::Escape($file)
switch -File $fileEscaped { foo { 'Foo' } }
# Foo