Alt du noen gang ønsket å vite om switch-setningen
- 03/01/2021
- 12 minutter å lese
-
- s
- c
- x
som mange andre språk, har powershell kommandoer for å kontrollere flyten av kjøring i yourscripts. En av disse uttalelsene er switch-setningen, og I PowerShell tilbyr den funksjoner som ikke finnes på andre språk. I dag tar vi et dypt dykk inn i å jobbe med PowerShellswitch
.
Merk
den opprinnelige versjonen av denne artikkelen dukket opp på bloggen skrevet av @ KevinMarquette. ThePowerShell teamet takk Kevin for å dele dette innholdet med oss. Vennligst sjekk ut hans blogg atPowerShellExplained.com.
if-setningen
en av de første setningene du lærer erif
– setningen. Det lar deg utføre et skriptblokkhvis en setning er $true
.
if ( Test-Path $Path ){ Remove-Item $Path}
du kan ha mye mer komplisert logikk ved å bruke elseif
og else
setninger. Her er et eksempelhvor jeg har en numerisk verdi for ukedag, og jeg vil få navnet som en streng.
$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 viser seg at dette er et vanlig mønster, og det er mange måter å håndtere dette på. En av dem er med en switch
.
Switch statement
switch
setningen lar deg gi en variabel og en liste over mulige verdier. Hvis verdienkamper variabelen, blir skriptblokken utført.
$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'
for dette eksemplet samsvarer verdien av $day
med en av de numeriske verdiene, og det riktige navnet tilordnes til $result
. Vi gjør bare en variabel oppgave i dette eksemplet, men Noen PowerShellcan utføres i disse skriptblokkene.
Tilordne til en variabel
Vi kan skrive det siste eksemplet på en annen måte.
$result = switch ( $day ){ 0 { 'Sunday' } 1 { 'Monday' } 2 { 'Tuesday' } 3 { 'Wednesday' } 4 { 'Thursday' } 5 { 'Friday' } 6 { 'Saturday' }}
vi plasserer verdien på PowerShell-rørledningen og tilordner den til $result
. Du kan gjøre det samme med if
og foreach
– setningene.
Standard
Vi kan brukedefault
søkeord for å identifisere hva som skal skje hvis det ikke er samsvar.
$result = switch ( $day ){ 0 { 'Sunday' } # ... 6 { 'Saturday' } default { 'Unknown' }}
her returnerer vi verdien Unknown
i standard tilfelle.
Strings
jeg var matchende tall i de siste eksemplene, men du kan også matche strenger.
$item = 'Role'switch ( $item ){ Component { 'is a component' } Role { 'is a role' } Location { 'is a location' }}
is a role
jeg bestemte meg for ikke å pakke innComponent
Role
ogLocation
kamper i sitater her for å markere thatthey ‘ re valgfritt. switch
behandler dem som en streng i de fleste tilfeller.
Arrays
En av de kule funksjonene I PowerShell switch
er måten den håndterer arrays. Hvis du gir enswitch
en matrise, behandler den hvert element i den samlingen.
$roles = @('WEB','Database')switch ( $roles ) { 'Database' { 'Configure SQL' } 'WEB' { 'Configure IIS' } 'FileServer' { 'Configure Share' }}
Configure IISConfigure SQL
hvis du har gjentatte elementer i arrayet ditt, blir de matchet flere ganger av appropriatesection.
PSItem
du kan bruke$PSItem
eller$_
for å referere til gjeldende element som ble behandlet. Når vi gjør asimple match,$PSItem
er verdien som vi samsvarer med. Jeg skal utføre noen avanserte matchesin neste avsnitt der denne variabelen brukes.
Parametere
En unik funksjon I PowerShell switch
er at den har en rekke bryterparametere somendre hvordan den utfører.
-CaseSensitive
matchene er ikke case-sensitive som standard. Hvis du trenger å være case-sensitive, kan du bruke -CaseSensitive
. Dette kan brukes i kombinasjon med de andre bryterparametrene.
-Wildcard
vi kan aktivere wildcard-støtte med bryteren -wildcard
. Dette bruker samme jokertegnlogikk som operatoren-like
for å gjøre hvert treff.
$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
her behandler vi en melding og sender den ut på forskjellige strømmer basert på innholdet.
-Regex
bryteren setningen støtter regex kamper akkurat som det gjør jokertegn.
switch -Regex ( $message ){ '^Error' { Write-Error -Message $Message } '^Warning' { Write-Warning -Message $Message } default { Write-Information $message }}
jeg har flere eksempler på å bruke regex i en annen artikkel jeg skrev: de mange måtene å bruke regex på.
-Fil
et lite kjent trekk ved switch-setningen er at den kan behandle en fil med parameteren -File
. Du bruker -file
med en bane til en fil i stedet for å gi den et variabelt uttrykk.
switch -Wildcard -File $path{ 'Error*' { Write-Error -Message $PSItem } 'Warning*' { Write-Warning -Message $PSItem } default { Write-Output $PSItem }}
det fungerer akkurat som å behandle en matrise. I dette eksemplet kombinerer jeg det med jokertegn og bruker $PSItem
. Dette vil behandle en loggfil og konvertere den til advarsel og errormessages avhengig av regex kamper.
Avanserte detaljer
Nå som du er klar over alle disse dokumenterte funksjonene, kan vi bruke dem i sammenheng med mer avansert behandling.
Uttrykk
switch
kan være på et uttrykk i stedet for en variabel.
switch ( ( Get-Service | Where status -eq 'running' ).name ) {...}
uansett hva uttrykket evaluerer til, er verdien som brukes for kampen.
Flere treff
du har kanskje allerede plukket opp dette, men en switch
kan matche flere forhold. Dette er spesielt sant når du bruker -wildcard
eller -regex
treff. Du kan legge til samme tilstand multipletimes og alle av dem er utløst.
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
alle tre av disse uttalelsene er avfyrt. Dette viser at hver tilstand er sjekket (i rekkefølge). Thisholds sant for behandling av arrays der hvert element sjekker hver tilstand.
Fortsett
Normalt er det her jeg vil introduserebreak
setningen, men det er bedre at vi lærer å brukecontinue
først. Akkurat som med en foreach
loop, continue
fortsetter til neste element inthe samlingen eller avslutter switch
hvis det ikke er flere elementer. Vi kan omskrive det siste eksempeletmed fortsette uttalelser slik at bare en setning utfører.
switch ( 'Word' ){ 'word' { 'lower case word match' continue } 'Word' { 'mixed case word match' continue } 'WORD' { 'upper case word match' continue }}
lower case word match
I Stedet for å matche alle tre elementene, blir den første matchet og bryteren fortsetter til neste verdi. Fordi det ikke er noen verdier igjen å behandle, går bryteren ut. Dette neste eksemplet viser hvordan et jokertegn kan matche flere elementer.
switch -Wildcard -File $path{ '*Error*' { Write-Error -Message $PSItem continue } '*Warning*' { Write-Warning -Message $PSItem continue } default { Write-Output $PSItem }}
fordi en linje i inngangsfilen kan inneholde både ordet Error
og Warning
, vil vi bare at den første skal utføre og deretter fortsette å behandle filen.
Pause
A break
setningen avslutter bryteren. Dette er den samme virkemåten som continue
presenterer for enkeltverdier. Forskjellen vises når du behandler en matrise. break
stopper all behandling i bryterenogcontinue
flytter til neste element.
$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 dette tilfellet, hvis vi treffer noen linjer som starter med Error
får vi en feil og bryteren stopper.Dette er hva som break
uttalelse gjør for oss. Hvis vi finner Error
inne i strengen og ikkebare i begynnelsen skriver vi det som en advarsel. Vi gjør det samme for Warning
. Det er mulig at en linje kan ha både ordet Error
og Warning
, men vi trenger bare en toprocess. Dette er hvacontinue
– setningen gjør for oss.
Bryt etiketter
switch
setningen støtterbreak/continue
etiketter akkurat 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 } }}
jeg personlig ikke liker bruk av bryte etiketter, men jeg ønsket å peke dem ut fordi de ‘ reconfusing hvis du aldri har sett dem før. Når du har flereswitch
ellerforeach
erklæringersom er nestet, vil du kanskje bryte ut av mer enn det indre elementet. Du kan plassere en labelon a switch
som kan være målet for din break
.
Enum
PowerShell 5.0 ga oss enums og vi kan bruke dem i en bryter.
enum Context { Component Role Location}$item = ::Roleswitch ( $item ){ Component { 'is a component' } Role { 'is a role' } Location { 'is a location' }}
is a role
hvis du vil beholde alt som sterkt skrevet enums, kan du plassere dem i parentes.
switch ($item ){ (::Component) { 'is a component' } (::Role) { 'is a role' } (::Location) { 'is a location' }}
parentesene er nødvendig her slik at bryteren ikke behandler verdien ::Location
asa bokstavelig streng.
ScriptBlock
Vi kan bruke en scriptblock for å utføre evalueringen for en kamp om nødvendig.
$age = 37switch ( $age ){ {$PSItem -le 18} { 'child' } {$PSItem -gt 18} { 'adult' }}
'adult'
dette legger til kompleksitet og kan gjøre switch
vanskelig å lese. I de fleste tilfeller hvor du vil brukenoe som dette ville det være bedre å brukeif
ogelseif
uttalelser. Jeg ville vurdere usingthis hvis jeg allerede hadde en stor bryter på plass, og jeg trengte to elementer for å treffe samme evaluationblock.
en ting som jeg tror hjelper med lesbarhet er å plassere skriptblokken i parentes.
switch ( $age ){ ({$PSItem -le 18}) { 'child' } ({$PSItem -gt 18}) { 'adult' }}
den utfører fortsatt på samme måte og gir en bedre visuell pause når du raskt ser på den.
Regex $matches
vi må besøke regex for å berøre noe som ikke er umiddelbart åpenbart. Bruken av regexpopulerer$matches
variabelen. Jeg går inn i bruken av$matches
mer når jeg snakker om mange måter å bruke regex på. Her er en rask prøve for å vise den i aksjon med navngitte kamper.
$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 matche en $null
verdi som ikke trenger å være standard.
$value = $nullswitch ( $value ){ $null { 'Value is null' } default { 'value is not null' }}```OutputValue is null
samme gjelder for en tom streng.
switch ( '' ){ '' { 'Value is empty' } default { 'value is a empty string' }}```OutputValue is empty
Konstant uttrykk
Lee Dailey påpekte at Vi kan bruke en konstant$true
uttrykk for å evaluere elementer.Tenk deg om vi har flere boolske kontroller som må skje.
$isVisible = $false$isEnabled = $true$isSecure = $trueswitch ( $true ){ $isEnabled { 'Do-Action' } $isVisible { 'Show-Animation' } $isSecure { 'Enable-AdminMenu' }}
Do-ActionEnabled-AdminMenu
dette er en ren måte å evaluere og iverksette tiltak på statusen til flere boolske felt. Thecool ting om dette er at du kan ha en kamp flip status for en verdi som ikke har beenevaluated ennå.
$isVisible = $false$isEnabled = $true$isAdmin = $falseswitch ( $true ){ $isEnabled { 'Do-Action' $isVisible = $true } $isVisible { 'Show-Animation' } $isAdmin { 'Enable-AdminMenu' }}
Do-ActionShow-Animation
Innstilling $isEnabled
til $true
i dette eksemplet sørger du for at $isVisible
også er satt til å$true
. Så når $isVisible
blir evaluert, blir dens scriptblock påkalt. Dette er en bitcounter-intuitiv, men er en smart bruk av mekanikken.
$switch automatisk variabel
når switch
behandler verdiene, oppretter den en enumerator og kaller den $switch
. Dette isan automatisk variabel opprettet Av PowerShell, og du kan manipulere den direkte.
$a = 1, 2, 3, 4switch($a) { 1 { $switch.MoveNext(); $switch.Current } 3 { $switch.MoveNext(); $switch.Current }}
dette gir deg resultatene av:
24
ved å flytte enumeratoren fremover, blir det neste elementet ikke behandlet av switch
men du kan få tilgang til denne verdien direkte. Jeg vil kalle det galskap.
Andre mønstre
Hashtables
En av mine mest populære innlegg er den jeg gjorde på hashtables. En av brukstilfellene for en hashtable
er å være et oppslagstabell. Det er en alternativ tilnærming til et vanlig mønster som enswitch
– setning ofte adresserer.
$day = 3$lookup = @{ 0 = 'Sunday' 1 = 'Monday' 2 = 'Tuesday' 3 = 'Wednesday' 4 = 'Thursday' 5 = 'Friday' 6 = 'Saturday'}$lookup
Wednesday
hvis jeg bare bruker enswitch
som et oppslag, bruker jeg ofte enhashtable
i stedet.
Enum
PowerShell 5.0 introduserte Enum
og det er også et alternativ i dette tilfellet.
$day = 3enum DayOfTheWeek { Sunday Monday Tuesday Wednesday Thursday Friday Saturday}$day
Wednesday
Vi kunne gå hele dagen og se på forskjellige måter å løse dette problemet på. Jeg ville bare forsikre meg om at du visste at du hadde alternativer.
Siste ord
switch-setningen er enkel på overflaten, men den tilbyr noen avanserte funksjoner som de fleste ikke skjønner er tilgjengelige. Strenger disse funksjonene sammen gjør dette til en kraftig funksjon. Jeg håper du lærte noe som du ikke hadde innsett før.