關於 switch 語句,您曾經想要知道的一切
與許多其他語言一樣,PowerShell 有命令可控制腳本內的執行流程。 其中一個語句是 switch 語句,在 PowerShell 中,它提供其他語言中找不到的功能。 今天,我們深入探討如何使用PowerShell switch
。
注意
本文的原始版本出現在@KevinMarquette撰寫的部落格上。 PowerShell 小組感謝 Kevin 與我們分享此內容。 請查看他在 PowerShellExplained.com 的部落格。
if
陳述式
您學習的第一個語句之一是 if
語句。 它可讓您在語句為 $true
時執行腳本區塊。
if ( Test-Path $Path )
{
Remove-Item $Path
}
您可以使用和 else
語句來擁有更複雜的邏輯elseif
。 以下是一個範例,其中我有星期幾的數值,而我想以字串的形式取得名稱。
$day = 3
if ( $day -eq 0 ) { $result = 'Sunday' }
elseif ( $day -eq 1 ) { $result = 'Monday' }
elseif ( $day -eq 2 ) { $result = 'Tuesday' }
elseif ( $day -eq 3 ) { $result = 'Wednesday' }
elseif ( $day -eq 4 ) { $result = 'Thursday' }
elseif ( $day -eq 5 ) { $result = 'Friday' }
elseif ( $day -eq 6 ) { $result = 'Saturday' }
$result
Wednesday
事實證明,這是一種常見的模式,有許多方式可以處理這種情況。 其中一個 switch
是使用 。
Switch 語句
switch
語句可讓您提供變數和可能值的清單。 如果值符合變數,則會執行其 scriptblock。
$day = 3
switch ( $day )
{
0 { $result = 'Sunday' }
1 { $result = 'Monday' }
2 { $result = 'Tuesday' }
3 { $result = 'Wednesday' }
4 { $result = 'Thursday' }
5 { $result = 'Friday' }
6 { $result = 'Saturday' }
}
$result
'Wednesday'
在這裡範例中,的值 $day
符合其中一個數值,然後將正確的名稱指派給 $result
。 我們在此範例中只會執行變數指派,但任何 PowerShell 都可以在這些腳本區塊中執行。
指派給變數
我們可以以另一種方式撰寫最後一個範例。
$result = switch ( $day )
{
0 { 'Sunday' }
1 { 'Monday' }
2 { 'Tuesday' }
3 { 'Wednesday' }
4 { 'Thursday' }
5 { 'Friday' }
6 { 'Saturday' }
}
我們會將值放在 PowerShell 管線上,並將它指派給 $result
。 您可以使用和 foreach
語句來執行相同的動作if
。
預設
我們可以使用 default
關鍵詞來識別如果沒有相符專案,應該會發生什麼事。
$result = switch ( $day )
{
0 { 'Sunday' }
# ...
6 { 'Saturday' }
default { 'Unknown' }
}
在此,我們會傳回預設案例中的值 Unknown
。
字串
我在最後一個範例中比對數位,但您也可以比對字串。
$item = 'Role'
switch ( $item )
{
Component
{
'is a component'
}
Role
{
'is a role'
}
Location
{
'is a location'
}
}
is a role
我決定不包裝 Component
,Role
並 Location
在這裡以引號比對,以強調它們是選擇性的。 在大部分情況下,會將 switch
那些視為字串。
陣列
PowerShell switch
的其中一個非經常性功能是處理數位的方式。 如果您提供 switch
陣列,它會處理該集合中的每個專案。
$roles = @('WEB','Database')
switch ( $roles ) {
'Database' { 'Configure SQL' }
'WEB' { 'Configure IIS' }
'FileServer' { 'Configure Share' }
}
Configure IIS
Configure SQL
如果您的陣列中重複專案,則適當區段會比對這些專案多次。
PSItem
您可以使用 $PSItem
或 $_
來參考處理過的目前專案。 當我們執行簡單的比對時, $PSItem
就是我們要比對的值。 我將在下一節中執行一些進階相符專案,在此區段中使用此變數。
參數
PowerShell switch
的獨特功能是它有一些參數,可變更其執行方式。
-CaseSensitive
根據預設,相符專案不會區分大小寫。 如果您需要區分大小寫,您可以使用 -CaseSensitive
。 這可以與其他參數搭配使用。
-通 配 符
我們可以使用 參數啟用通配符支援 -wildcard
。 這會使用與 -like
運算子相同的通配符邏輯來執行每個比對。
$Message = 'Warning, out of disk space'
switch -Wildcard ( $message )
{
'Error*'
{
Write-Error -Message $Message
}
'Warning*'
{
Write-Warning -Message $Message
}
default
{
Write-Information $message
}
}
WARNING: Warning, out of disk space
我們在這裡正在處理訊息,然後根據內容將它輸出到不同的數據流上。
-Regex
switch 語句支援 regex 比對,就像它執行通配符一樣。
switch -Regex ( $message )
{
'^Error'
{
Write-Error -Message $Message
}
'^Warning'
{
Write-Warning -Message $Message
}
default
{
Write-Information $message
}
}
我在另一篇文章中有更多使用 regex 的範例: 使用 regex 的許多方式。
-檔
switch 語句的一個鮮為人知的功能是,它可以使用 -File
參數來處理檔案。 您可以搭配檔案的路徑使用 -file
,而不是為檔案提供變數表達式。
switch -Wildcard -File $path
{
'Error*'
{
Write-Error -Message $PSItem
}
'Warning*'
{
Write-Warning -Message $PSItem
}
default
{
Write-Output $PSItem
}
}
其運作方式就像處理陣列一樣。 在這裡範例中,我將它與通配符比對結合,並使用 $PSItem
。 這會處理記錄檔,並根據 regex 相符專案,將其轉換成警告和錯誤訊息。
進階詳細數據
既然您已瞭解所有這些記載的功能,我們可以在更進階處理的內容中使用這些功能。
運算式
switch
可以在表達式上,而不是變數。
switch ( ( Get-Service | Where status -eq 'running' ).name ) {...}
無論表達式評估為 什麼,都是用於比對的值。
多個相符專案
您可能已經對此有所取用,但 可以 switch
符合多個條件。 使用 -wildcard
或 -regex
比對時尤其如此。 您可以多次新增相同的條件,並全部觸發。
switch ( 'Word' )
{
'word' { 'lower case word match' }
'Word' { 'mixed case word match' }
'WORD' { 'upper case word match' }
}
lower case word match
mixed case word match
upper case word match
這三個語句都會引發。 這會顯示已核取每個條件(依序)。 這適用於處理每個項目檢查每個條件的數位。
繼續
通常,這就是我要介紹語句的地方 break
,但最好先瞭解如何使用 continue
。 就像循環一 foreach
樣,繼續進行集合中的下一個專案,如果沒有其他專案, continue
就會結束 switch
。 我們可以使用continue語句重寫最後一個範例,以便只執行一個語句。
switch ( 'Word' )
{
'word'
{
'lower case word match'
continue
}
'Word'
{
'mixed case word match'
continue
}
'WORD'
{
'upper case word match'
continue
}
}
lower case word match
第一個專案不會比對這三個專案,而是會比對第一個專案,而參數會繼續下一個值。 因為沒有任何值可供處理,因此參數會結束。 下一個範例示範通配符如何比對多個專案。
switch -Wildcard -File $path
{
'*Error*'
{
Write-Error -Message $PSItem
continue
}
'*Warning*'
{
Write-Warning -Message $PSItem
continue
}
default
{
Write-Output $PSItem
}
}
因為輸入檔中的一行可以同時包含 和 Warning
,Error
所以我們只想要執行第一行,然後繼續處理檔案。
休息時間
break
語句會結束 參數。 這是針對單一值呈現的相同行為 continue
。 處理陣列時會顯示差異。 break
停止參數中的所有處理,並 continue
移至下一個專案。
$Messages = @(
'Downloading update'
'Ran into errors downloading file'
'Error: out of disk space'
'Sending email'
'...'
)
switch -Wildcard ($Messages)
{
'Error*'
{
Write-Error -Message $PSItem
break
}
'*Error*'
{
Write-Warning -Message $PSItem
continue
}
'*Warning*'
{
Write-Warning -Message $PSItem
continue
}
default
{
Write-Output $PSItem
}
}
Downloading update
WARNING: Ran into errors downloading file
write-error -message $PSItem : Error: out of disk space
+ CategoryInfo : NotSpecified: (:) [Write-Error], WriteErrorException
+ FullyQualifiedErrorId : Microsoft.PowerShell.Commands.WriteErrorException
在此情況下,如果我們叫用任何開頭 Error
的行,就會收到錯誤,而切換會停止。
這就是 break
語句為我們所做的。 如果我們在字串內找到 Error
,而不只是在開頭,我們會將其寫入為警告。 我們對 執行相同的動作 Warning
。 一行可以同時有 和 Warning
這兩個字Error
,但我們只需要一個來處理。 這就是 continue
語句為我們所做的。
中斷標籤
switch
語句支持break/continue
標籤,就像 一樣foreach
。
:filelist foreach($path in $logs)
{
:logFile switch -Wildcard -File $path
{
'Error*'
{
Write-Error -Message $PSItem
break filelist
}
'Warning*'
{
Write-Error -Message $PSItem
break logFile
}
default
{
Write-Output $PSItem
}
}
}
我個人不喜歡使用中斷卷標,但我想指出它們,因為他們令人困惑,如果你以前從未見過它們。 當您有多個 switch
或 foreach
語句巢狀時,可能會想要突破超過最內層的專案。 您可以將標籤放在 上,該標籤 switch
可以是 您 break
的目標。
列舉
PowerShell 5.0 提供列舉,我們可以在參數中使用它們。
enum Context {
Component
Role
Location
}
$item = [Context]::Role
switch ( $item )
{
Component
{
'is a component'
}
Role
{
'is a role'
}
Location
{
'is a location'
}
}
is a role
如果您想要將所有專案保留為強型別列舉,您可以將它們放在括弧中。
switch ($item )
{
([Context]::Component)
{
'is a component'
}
([Context]::Role)
{
'is a role'
}
([Context]::Location)
{
'is a location'
}
}
此處需要括弧,因此參數不會將值視為常值 [Context]::Location
字串。
ScriptBlock
我們可以使用 scriptblock,視需要執行比對的評估。
$age = 37
switch ( $age )
{
{$PSItem -le 18}
{
'child'
}
{$PSItem -gt 18}
{
'adult'
}
}
'adult'
這會增加複雜性,並可讓您 switch
難以閱讀。 在大部分情況下,您會使用類似這樣的專案,最好是使用 if
和 elseif
語句。 如果我已經有一個大開關,我需要兩個項目來達到相同的評估區塊,我會考慮使用這個。
我認為有助於辨別的一件事是將腳本區塊放在括弧中。
switch ( $age )
{
({$PSItem -le 18})
{
'child'
}
({$PSItem -gt 18})
{
'adult'
}
}
它仍然以相同的方式執行,並在快速查看它時提供更好的視覺中斷。
Regex $matches
我們需要重新流覽 regex,以接觸一些不明顯的東西。 regex 的使用會填入 $matches
變數。 當我談論許多使用 regex 的方式時, 我確實會更多地使用$matches
。 以下是使用具名相符項目運作的快速範例。
$message = 'my ssn is 123-23-3456 and credit card: 1234-5678-1234-5678'
switch -regex ($message)
{
'(?<SSN>\d\d\d-\d\d-\d\d\d\d)'
{
Write-Warning "message contains a SSN: $($matches.SSN)"
}
'(?<CC>\d\d\d\d-\d\d\d\d-\d\d\d\d-\d\d\d\d)'
{
Write-Warning "message contains a credit card number: $($matches.CC)"
}
'(?<Phone>\d\d\d-\d\d\d-\d\d\d\d)'
{
Write-Warning "message contains a phone number: $($matches.Phone)"
}
}
WARNING: message may contain a SSN: 123-23-3456
WARNING: message may contain a credit card number: 1234-5678-1234-5678
$null
您可以比 $null
對不一定是預設值的值。
$values = '', 5, $null
switch ( $values )
{
$null { "Value '$_' is `$null" }
{ '' -eq $_ } { "Value '$_' is an empty string" }
default { "Value [$_] isn't an empty string or `$null" }
}
Value '' is an empty string
Value [5] isn't an empty string or $null
Value '' is $null
在語句中 switch
測試空字串時,請務必使用比較語句,如本範例所示,而不是原始值 ''
。 switch
在語句中,原始值''
也會比對 $null
。 例如:
$values = '', 5, $null
switch ( $values )
{
$null { "Value '$_' is `$null" }
'' { "Value '$_' is an empty string" }
default { "Value [$_] isn't an empty string or `$null" }
}
Value '' is an empty string
Value [5] isn't an empty string or $null
Value '' is $null
Value '' is an empty string
此外,請小心從 Cmdlet 傳回空的傳回。 沒有輸出的 Cmdlet 或管線會被視為不符合任何專案的空陣列,包括 default
案例。
$file = Get-ChildItem NonExistantFile*
switch ( $file )
{
$null { '$file is $null' }
default { "`$file is type $($file.GetType().Name)" }
}
# No matches
常數表達式
李戴利指出,我們可以使用常數 $true
表達式來評估 [bool]
專案。
想像一下,如果我們有數個需要發生的布爾值檢查。
$isVisible = $false
$isEnabled = $true
$isSecure = $true
switch ( $true )
{
$isEnabled
{
'Do-Action'
}
$isVisible
{
'Show-Animation'
}
$isSecure
{
'Enable-AdminMenu'
}
}
Do-Action
Enabled-AdminMenu
這是評估及對數個布爾值字段狀態採取動作的全新方式。 這個很酷的事情是,您可以讓一個相符專案翻轉尚未評估的值狀態。
$isVisible = $false
$isEnabled = $true
$isAdmin = $false
switch ( $true )
{
$isEnabled
{
'Do-Action'
$isVisible = $true
}
$isVisible
{
'Show-Animation'
}
$isAdmin
{
'Enable-AdminMenu'
}
}
Do-Action
Show-Animation
在這裡範例中會設定$isEnabled
為 ,可確保 $isVisible
也設定為 $true
$true
。
然後,評估時 $isVisible
會叫用其 scriptblock。 這是一個有點反直覺,但是巧妙的使用機制。
$switch自動變數
switch
當 正在處理其值時,它會建立列舉值並呼叫它$switch
。 這是 PowerShell 所建立的自動變數,您可以直接操作它。
$a = 1, 2, 3, 4
switch($a) {
1 { [void]$switch.MoveNext(); $switch.Current }
3 { [void]$switch.MoveNext(); $switch.Current }
}
這可讓您取得下列結果:
2
4
藉由向前移動列舉值,下一個專案不會由 switch
處理,但您可以直接存取該值。 我會稱之為瘋狂。
其他模式
哈希表
我最受歡迎的文章之一是我在哈希表上 所做的文章。 的其中一個使用案例 hashtable
是查閱表格。 這是語句經常處理之常見模式 switch
的替代方法。
$day = 3
$lookup = @{
0 = 'Sunday'
1 = 'Monday'
2 = 'Tuesday'
3 = 'Wednesday'
4 = 'Thursday'
5 = 'Friday'
6 = 'Saturday'
}
$lookup[$day]
Wednesday
如果我只是使用 switch
做為查閱,我通常會改用 。hashtable
列舉
PowerShell 5.0 引進 Enum
了 ,在此案例中也是一個選項。
$day = 3
enum DayOfTheWeek {
Sunday
Monday
Tuesday
Wednesday
Thursday
Friday
Saturday
}
[DayOfTheWeek]$day
Wednesday
我們可以整天研究解決這個問題的不同方式。 我只是想確保你知道你有選擇。
最後一個字
switch 語句在表面上很簡單,但它提供了一些大多數人無法意識到的進階功能。 將這些功能串在一起會使此功能成為功能強大的功能。 我希望你學到了你以前沒有意識到的東西。
意見反應
https://aka.ms/ContentUserFeedback。
即將登場:在 2024 年,我們將逐步淘汰 GitHub 問題作為內容的意見反應機制,並將它取代為新的意見反應系統。 如需詳細資訊,請參閱:提交並檢視相關的意見反應