allt du någonsin velat veta om switch uttalande
- 03/01/2021
- 12 minuter att läsa
-
- s
- c
- X
liksom många andra språk har PowerShell kommandon för att styra flödet av körning inom yourscripts. Ett av dessa uttalanden är switch-uttalandet och i PowerShell erbjuder det funktioner som inte finns på andra språk. Idag tar vi ett djupt dyk i att arbeta med PowerShellswitch
.
Obs
den ursprungliga versionen av denna artikel dök upp på bloggen skriven av @KevinMarquette. ThePowerShell team tack Kevin för att dela detta innehåll med oss. Vänligen kolla in hans blogg atPowerShellExplained.com.
if-uttalandet
en av de första uttalandena som du lär dig ärif
– uttalandet. Det låter dig köra ett skriptblock om ett uttalande är $true
.
if ( Test-Path $Path ){ Remove-Item $Path}
Du kan ha mycket mer komplicerad logik genom att använda elseif
och else
uttalanden. Här är ett exempeldär jag har ett numeriskt värde för veckodag och jag vill få namnet som en sträng.
$day = 3if ( $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
det visar sig att detta är ett vanligt mönster och det finns många sätt att hantera detta. Oneof dem är med en switch
.
Switch statement
switch
– satsen låter dig ange en variabel och en lista över möjliga värden. Om värdetmatchar variabeln, körs dess scriptblock.
$day = 3switch ( $day ){ 0 { $result = 'Sunday' } 1 { $result = 'Monday' } 2 { $result = 'Tuesday' } 3 { $result = 'Wednesday' } 4 { $result = 'Thursday' } 5 { $result = 'Friday' } 6 { $result = 'Saturday' }}$result
'Wednesday'
för detta exempel matchar värdet på $day
ett av de numeriska värdena, då är det korrekta namnet tilldelat $result
. Vi gör bara en variabel uppgift i det här exemplet, men alla PowerShell kan utföras i dessa skriptblock.
tilldela en variabel
Vi kan skriva det sista exemplet på ett annat sätt.
$result = switch ( $day ){ 0 { 'Sunday' } 1 { 'Monday' } 2 { 'Tuesday' } 3 { 'Wednesday' } 4 { 'Thursday' } 5 { 'Friday' } 6 { 'Saturday' }}
vi placerar värdet på PowerShell-rörledningen och tilldelar det till $result
. Du kan göraDetta samma sak medif
ochforeach
uttalanden.
standard
Vi kan använda default
för att identifiera vad som ska hända om det inte finns någon matchning.
$result = switch ( $day ){ 0 { 'Sunday' } # ... 6 { 'Saturday' } default { 'Unknown' }}
här returnerar vi värdet Unknown
I standardfallet.
strängar
jag matchade siffror i de sista exemplen, men du kan också matcha strängar.
$item = 'Role'switch ( $item ){ Component { 'is a component' } Role { 'is a role' } Location { 'is a location' }}
is a role
jag bestämde mig för att inte sätta in Component
Role
och Location
matchar i citat här för att markera detde är valfria. switch
behandlar dem som en sträng i de flesta fall.
Arrays
en av de coola funktionerna i PowerShellswitch
är hur den hanterar arrays. Om du ger enswitch
en array, bearbetar den varje element i den samlingen.
$roles = @('WEB','Database')switch ( $roles ) { 'Database' { 'Configure SQL' } 'WEB' { 'Configure IIS' } 'FileServer' { 'Configure Share' }}
Configure IISConfigure SQL
Om du har upprepade objekt i din array matchas de flera gånger av lämpligt avsnitt.
PSItem
Du kan använda $PSItem
eller $_
för att referera till det aktuella objektet som behandlades. När vi gör en enkel matchning är$PSItem
det värde som vi matchar. Jag kommer att utföra några avancerade matchesi nästa avsnitt där denna variabel används.
parametrar
en unik egenskap hos PowerShell switch
är att den har ett antal omkopplarparametrar somändra hur det fungerar.
-CaseSensitive
matchningarna är inte skiftlägeskänsliga som standard. Om du behöver vara skiftlägeskänslig kan du använda-CaseSensitive
. Detta kan användas i kombination med de andra omkopplarparametrarna.
-jokertecken
Vi kan aktivera jokerstöd med-wildcard
switch. Detta använder samma jokertecken logik som-like
operatör för att göra varje match.
$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
här bearbetar vi ett meddelande och matar sedan ut det på olika strömmar baserat på innehållet.
-Regex
switch-uttalandet stöder regex-matchningar precis som det gör jokertecken.
switch -Regex ( $message ){ '^Error' { Write-Error -Message $Message } '^Warning' { Write-Warning -Message $Message } default { Write-Information $message }}
Jag har fler exempel på att använda regex i en annan artikel Jag skrev: de många sätten att använda regex.
-File
en lite känd funktion i switch-uttalandet är att den kan bearbeta en fil med parametern -File
. Du använder -file
med en sökväg till en fil istället för att ge den ett variabelt uttryck.
switch -Wildcard -File $path{ 'Error*' { Write-Error -Message $PSItem } 'Warning*' { Write-Warning -Message $PSItem } default { Write-Output $PSItem }}
det fungerar precis som att bearbeta en array. I det här exemplet kombinerar jag det med jokerteckenmatchning ochanvänd $PSItem
. Detta skulle bearbeta en loggfil och konvertera den till varning och felmeddelanden beroende på regex-matchningarna.
avancerade detaljer
Nu när du är medveten om alla dessa dokumenterade funktioner kan vi använda dem i samband med meravancerad bearbetning.
uttryck
switch
kan vara på ett uttryck istället för en variabel.
switch ( ( Get-Service | Where status -eq 'running' ).name ) {...}
vad uttrycket utvärderar till är det värde som används för matchningen.
flera matchningar
Du kanske redan har plockat upp detta, men ett switch
kan matcha flera villkor. Detta är särskilt sant när du använder-wildcard
eller-regex
matchar. Du kan lägga till samma villkor multipletimes och alla av dem utlöses.
switch ( 'Word' ){ 'word' { 'lower case word match' } 'Word' { 'mixed case word match' } 'WORD' { 'upper case word match' }}
lower case word matchmixed case word matchupper case word match
alla tre av dessa uttalanden avfyras. Detta visar att varje villkor kontrolleras (i ordning). Thisholds sant för bearbetning arrays där varje objekt kontrollerar varje villkor.
Fortsätt
normalt är det här jag skulle introducerabreak
uttalande, men det är bättre att vi lär oss huratt användacontinue
först. Precis som med en foreach
loop, continue
fortsätter till nästa punkt i samlingen eller avslutar switch
om det inte finns fler objekt. Vi kan skriva om det sista exempeletmed fortsätt uttalanden så att endast ett uttalande körs.
switch ( 'Word' ){ 'word' { 'lower case word match' continue } 'Word' { 'mixed case word match' continue } 'WORD' { 'upper case word match' continue }}
lower case word match
istället för att matcha alla tre objekten matchas den första och omkopplaren fortsätter till nästa värde. Eftersom det inte finns några värden kvar att bearbeta, går omkopplaren ut. Detta nästa exempel visarhur ett jokertecken kan matcha flera objekt.
switch -Wildcard -File $path{ '*Error*' { Write-Error -Message $PSItem continue } '*Warning*' { Write-Warning -Message $PSItem continue } default { Write-Output $PSItem }}
eftersom en rad i inmatningsfilen kan innehålla både ordet Error
och Warning
, vill vi bara att den första ska köras och sedan fortsätta bearbeta filen.
Break
A break
uttalande lämnar omkopplaren. Detta är samma beteende somcontinue
presenterar för singlevalues. Skillnaden visas vid bearbetning av en matris. break
stoppar all bearbetning i omkopplaren ochcontinue
flyttas till nästa objekt.
$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 updateWARNING: Ran into errors downloading filewrite-error -message $PSItem : Error: out of disk space+ CategoryInfo : NotSpecified: (:) , WriteErrorException+ FullyQualifiedErrorId : Microsoft.PowerShell.Commands.WriteErrorException
i det här fallet, om vi träffar några rader som börjar med Error
då får vi ett fel och omkopplaren stannar.Detta är vad detbreak
uttalande gör för oss. Om vi hittar Error
inuti strängen och intebara i början skriver vi det som en varning. Vi gör samma sak för Warning
. Det är möjligt att en rad kan ha både ordet Error
och Warning
, men vi behöver bara en toprocess. Detta är vadcontinue
uttalande gör för oss.
Break etiketter
switch
uttalande stöderbreak/continue
etiketter precis somforeach
.
: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 } }}
Jag gillar personligen inte användningen av brytetiketter men jag ville påpeka dem eftersom de ’ reconfusing om du aldrig har sett dem tidigare. När du har fleraswitch
ellerforeach
uttalandensom är kapslade kanske du vill bryta ut mer än det inre mest objektet. Du kan placera en labelon a switch
som kan vara målet för ditt break
.
Enum
PowerShell 5.0 gav oss enums och vi kan använda dem i en switch.
enum Context { Component Role Location}$item = ::Roleswitch ( $item ){ Component { 'is a component' } Role { 'is a role' } Location { 'is a location' }}
is a role
Om du vill behålla allt så starkt skrivna enums kan du placera dem inom parentes.
switch ($item ){ (::Component) { 'is a component' } (::Role) { 'is a role' } (::Location) { 'is a location' }}
parenteserna behövs här så att omkopplaren inte behandlar värdet::Location
Asa bokstavlig sträng.
ScriptBlock
Vi kan använda ett scriptblock för att utföra utvärderingen för en matchning om det behövs.
$age = 37switch ( $age ){ {$PSItem -le 18} { 'child' } {$PSItem -gt 18} { 'adult' }}
'adult'
detta lägger till komplexitet och kan göra ditt switch
svårt att läsa. I de flesta fall där du skulle användanågot så här skulle det vara bättre att använda if
och elseif
uttalanden. Jag skulle överväga att använda detta om jag redan hade en stor omkopplare på plats och jag behövde två saker för att träffa samma utvärderingsblock.
en sak som jag tror hjälper till med läsbarhet är att placera scriptblock inom parentes.
switch ( $age ){ ({$PSItem -le 18}) { 'child' } ({$PSItem -gt 18}) { 'adult' }}
det körs fortfarande på samma sätt och ger en bättre visuell paus när man snabbt tittar på den.
Regex $matchar
Vi måste återkomma regex för att beröra något som inte är omedelbart uppenbart. Användningen av regexpopulates$matches
variabel. Jag går in i användningen av $matches
mer när jag pratar omde många sätten att använda regex. Här är ett snabbt prov för att visa det i aktion med namngivna matchningar.
$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-3456WARNING: message may contain a credit card number: 1234-5678-1234-5678
$null
Du kan matcha ett $null
värde som inte behöver vara standard.
$value = $nullswitch ( $value ){ $null { 'Value is null' } default { 'value is not null' }}```OutputValue is null
samma gäller för en tom sträng.
switch ( '' ){ '' { 'Value is empty' } default { 'value is a empty string' }}```OutputValue is empty
konstant uttryck
Lee Dailey påpekade att vi kan använda en konstant $true
uttryck för att utvärdera objekt.Tänk om vi har flera booleska kontroller som måste hända.
$isVisible = $false$isEnabled = $true$isSecure = $trueswitch ( $true ){ $isEnabled { 'Do-Action' } $isVisible { 'Show-Animation' } $isSecure { 'Enable-AdminMenu' }}
Do-ActionEnabled-AdminMenu
detta är ett rent sätt att utvärdera och vidta åtgärder för status för flera booleska fält. Thecool sak om detta är att du kan ha en match vända status för ett värde som inte har utvärderats ännu.
$isVisible = $false$isEnabled = $true$isAdmin = $falseswitch ( $true ){ $isEnabled { 'Do-Action' $isVisible = $true } $isVisible { 'Show-Animation' } $isAdmin { 'Enable-AdminMenu' }}
Do-ActionShow-Animation
inställning $isEnabled
till $true
I det här exemplet ser du till att $isVisible
också är inställt på$true
. Sedan när $isVisible
utvärderas, anropas dess scriptblock. Detta är en bitcounter-intuitivt men är en smart användning av mekaniken.
$switch automatisk variabel
närswitch
bearbetar dess värden skapar den en uppräkare och kallar den$switch
. Detta är en automatisk variabel skapad av PowerShell och du kan manipulera den direkt.
$a = 1, 2, 3, 4switch($a) { 1 { $switch.MoveNext(); $switch.Current } 3 { $switch.MoveNext(); $switch.Current }}
detta ger dig resultaten av:
24
genom att flytta uppräknaren framåt behandlas nästa objekt inte av switch
men du kanåtgång till det värdet direkt. Jag skulle kalla det galenskap.
andra mönster
Hashtables
ett av mina mest populära inlägg är det jag gjorde på hashtables. Ett av användningsfallen för etthashtable
är att vara en uppslagstabell. Det är ett alternativt tillvägagångssätt för ett gemensamt mönster som ettswitch
– uttalande ofta adresserar.
$day = 3$lookup = @{ 0 = 'Sunday' 1 = 'Monday' 2 = 'Tuesday' 3 = 'Wednesday' 4 = 'Thursday' 5 = 'Friday' 6 = 'Saturday'}$lookup
Wednesday
Om jag bara använder ett switch
som en sökning använder jag ofta ett hashtable
istället.
Enum
PowerShell 5.0 introducerade Enum
och det är också ett alternativ i det här fallet.
$day = 3enum DayOfTheWeek { Sunday Monday Tuesday Wednesday Thursday Friday Saturday}$day
Wednesday
Vi kan gå hela dagen och titta på olika sätt att lösa detta problem. Jag ville bara se till att du visste att du hade alternativ.
sista ord
omkopplingsuttalandet är enkelt på ytan men det erbjuder några avancerade funktioner som de flesta människor inte inser är tillgängliga. Att stränga dessa funktioner tillsammans gör detta till en kraftfull funktion. Jag hoppas att du lärde dig något som du inte hade insett tidigare.