tot ce ați dorit vreodată să știți despre declarația switch
- 03/01/2021
- 12 minute pentru a citi
-
- s
- c
- x
ca multe alte limbi, PowerShell are comenzi pentru controlul fluxului de execuție în cadrul dvs. scripturi. Una dintre aceste afirmații este instrucțiunea switch și în PowerShell, oferă caracteristici care nu se găsesc în alte limbi. Astăzi, facem o scufundare profundă în lucrul cu PowerShell switch
.
notă
Versiunea originală a acestui articol a apărut pe blogul scris de @KevinMarquette. Echipa ThePowerShell îi mulțumește lui Kevin pentru că ne-a împărtășit acest conținut. Vă rugăm să verificați blogul său atPowerShellExplained.com.
instrucțiunea if
una dintre primele afirmații pe care le învățați esteif
. Acesta vă permite să executați un script blockif o declarație este $true
.
if ( Test-Path $Path ){ Remove-Item $Path}
puteți avea o logică mult mai complicată folosindelseif
șielse
declarații. Iată un exempluunde am o valoare numerică pentru ziua săptămânii și vreau să obțin numele ca șir.
$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
se pare că acesta este un model comun și există multe modalități de a face față acestui lucru. Unul dintre ele este cu un switch
.
declarație comutator
switch
declarație vă permite să furnizați o variabilă și o listă de valori posibile. Dacă valuematches variabila, atunci scriptblock-ul său este executat.
$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'
pentru acest exemplu, valoarea $day
se potrivește cu una dintre valorile numerice, apoi numele corect este atribuit $result
. Facem doar o atribuire variabilă în acest exemplu, dar orice Powershellpoate fi executat în acele blocuri de script.
atribuiți unei variabile
putem scrie acest ultim exemplu într-un alt mod.
$result = switch ( $day ){ 0 { 'Sunday' } 1 { 'Monday' } 2 { 'Tuesday' } 3 { 'Wednesday' } 4 { 'Thursday' } 5 { 'Friday' } 6 { 'Saturday' }}
plasăm valoarea pe conducta PowerShell și o atribuim$result
. Puteți face același lucru cu if
și foreach
declarații.
implicit
putem folosidefault
cuvinte cheie pentru a identifica ceea ce ar trebui să se întâmple dacă nu există nici o potrivire.
$result = switch ( $day ){ 0 { 'Sunday' } # ... 6 { 'Saturday' } default { 'Unknown' }}
aici returnăm valoarea Unknown
în cazul implicit.
siruri de caractere
am fost de potrivire numere în aceste ultime exemple, dar puteți potrivi, de asemenea, siruri de caractere.
$item = 'Role'switch ( $item ){ Component { 'is a component' } Role { 'is a role' } Location { 'is a location' }}
is a role
am decis să nu împachetez Component
Role
și Location
se potrivește în ghilimele aici pentru a evidenția acest lucruele sunt opționale. switch
le tratează ca un șir în majoritatea cazurilor.
Arrays
una dintre caracteristicile interesante ale PowerShellswitch
este modul în care se ocupă de matrice. Dacă dați unswitch
o matrice, procesează fiecare element din acea colecție.
$roles = @('WEB','Database')switch ( $roles ) { 'Database' { 'Configure SQL' } 'WEB' { 'Configure IIS' } 'FileServer' { 'Configure Share' }}
Configure IISConfigure SQL
Dacă aveți elemente repetate în matrice, atunci acestea sunt potrivite de mai multe ori de către secțiunea corespunzătoare.
PSItem
puteți utiliza$PSItem
sau$_
pentru a face referire la elementul curent care a fost procesat. Când facem potrivirea simplă, $PSItem
este valoarea pe care o potrivim. Voi efectua unele matchesin avansate secțiunea următoare în cazul în care această variabilă este utilizată.
parametri
o caracteristică unică a PowerShellswitch
este că are un număr de parametri de comutare careschimba modul în care efectuează.
-CaseSensitive
meciurile nu sunt sensibile la majuscule în mod implicit. Dacă trebuie să fiți sensibil la majuscule, puteți utiliza-CaseSensitive
. Acest lucru poate fi utilizat în combinație cu ceilalți parametri de comutare.
-Wildcard
putem activa suportul wildcard cu comutatorul-wildcard
. Aceasta folosește aceeași logică wildcard ca operatorul-like
pentru a face fiecare meci.
$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
aici procesăm un mesaj și apoi îl afișăm pe diferite fluxuri bazate pe conținut.
-Regex
instrucțiunea switch acceptă potrivirile regex la fel ca și metacaracterele.
switch -Regex ( $message ){ '^Error' { Write-Error -Message $Message } '^Warning' { Write-Warning -Message $Message } default { Write-Information $message }}
am mai multe exemple de utilizare a regex într-un alt articol pe care l-am scris: numeroasele moduri de utilizare a regex.
-File
o caracteristică puțin cunoscută a instrucțiunii switch este că poate procesa un fișier cu parametrul-File
. Utilizați -file
cu o cale către un fișier în loc să-i dați o expresie variabilă.
switch -Wildcard -File $path{ 'Error*' { Write-Error -Message $PSItem } 'Warning*' { Write-Warning -Message $PSItem } default { Write-Output $PSItem }}
funcționează la fel ca procesarea unei matrice. În acest exemplu, îl combin cu potrivirea wildcard șifolosiți $PSItem
. Acest lucru ar procesa un fișier jurnal și converti la avertizare și errormessages în funcție de meciurile regex.
detalii avansate
acum, că sunteți la curent cu toate aceste caracteristici documentate, le putem folosi în contextul procesării mai avansate.
expresii
switch
poate fi pe o expresie în loc de o variabilă.
switch ( ( Get-Service | Where status -eq 'running' ).name ) {...}
orice expresie evaluează este valoarea utilizată pentru potrivire.
potriviri Multiple
este posibil să fi preluat deja acest lucru, dar unswitch
se poate potrivi cu mai multe condiții. Acest lucru este valabil mai ales atunci când se utilizează-wildcard
sau-regex
meciuri. Puteți adăuga aceeași condiție multipletimes și toate acestea sunt declanșate.
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
toate aceste trei declarații sunt trase. Acest lucru arată că fiecare condiție este verificată (în ordine). Thisholds adevărat pentru matrice de prelucrare în cazul în care fiecare element verifică fiecare condiție.
continuare
în mod normal, aici aș introducebreak
declarație, dar este mai bine să învățăm cum să folosimcontinue
mai întâi. La fel ca în cazul unei foreach
buclă, continue
continuă pe următorul element din colecție sau iese din switch
dacă nu mai există elemente. Putem rescrie acest ultim exemplucu declarații continue, astfel încât să se execute o singură declarație.
switch ( 'Word' ){ 'word' { 'lower case word match' continue } 'Word' { 'mixed case word match' continue } 'WORD' { 'upper case word match' continue }}
lower case word match
în loc să se potrivească cu toate cele trei elemente, primul este potrivit și comutatorul continuă la valoarea următoare. Deoarece nu mai există valori de procesat, comutatorul iese. Acest exemplu următor arată cum un wildcard ar putea potrivi Mai multe elemente.
switch -Wildcard -File $path{ '*Error*' { Write-Error -Message $PSItem continue } '*Warning*' { Write-Warning -Message $PSItem continue } default { Write-Output $PSItem }}
deoarece o linie din fișierul de intrare ar putea conține atât cuvântulError
șiWarning
, vrem doar ca primul să execute și apoi să continue procesarea fișierului.
Break
obreak
iese din comutator. Acesta este același comportament care continue
prezintă pentru singlevalues. Diferența este afișată la procesarea unei matrice. break
OPREȘTE toată procesarea în comutatorși continue
se mută pe următorul 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
În acest caz, dacă lovim linii care încep cu Error
atunci primim o eroare și comutatorul se oprește.Aceasta este ceea ce face acea declarație break
pentru noi. Dacă găsim Error
în interiorul șirului și nudoar la început, îl scriem ca un avertisment. Facem același lucru pentru Warning
. Este posibil ca o linie să aibă atât cuvântul Error
, cât și Warning
, dar avem nevoie doar de un singur proces. Aceasta este ceea ce face declarația continue
pentru noi.
Break etichete
switch
declarație acceptăbreak/continue
etichete la fel caforeach
.
: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 } }}
eu personal nu-mi place utilizarea de etichete pauză, dar am vrut să le subliniez pentru că they ‘ reconfusing dacă nu le-ați văzut înainte. Când aveți mai multeswitch
sauforeach
declarațiicare sunt imbricate, poate doriți să ieșiți din mai mult decât elementul cel mai interior. Puteți plasa o etichetă pe un switch
care poate fi țintabreak
.
Enum
PowerShell 5.0 ne-a dat enums și le putem folosi într-un comutator.
enum Context { Component Role Location}$item = ::Roleswitch ( $item ){ Component { 'is a component' } Role { 'is a role' } Location { 'is a location' }}
is a role
Dacă doriți să păstrați totul la fel de puternic tastat enums, atunci le puteți plasa între paranteze.
switch ($item ){ (::Component) { 'is a component' } (::Role) { 'is a role' } (::Location) { 'is a location' }}
parantezele sunt necesare aici, astfel încât comutatorul să nu trateze valoarea::Location
asa șir literal.
ScriptBlock
putem folosi un scriptblock pentru a efectua evaluarea pentru un meci, dacă este necesar.
$age = 37switch ( $age ){ {$PSItem -le 18} { 'child' } {$PSItem -gt 18} { 'adult' }}
'adult'
aceasta adaugă complexitate și vă poate faceswitch
greu de citit. În majoritatea cazurilor în care ați utilizaceva de genul acesta ar fi mai bine să utilizați if
și elseif
declarații. Mi-ar lua în considerare usingthis dacă am avut deja un comutator mare în loc și am nevoie de două elemente pentru a lovi același evaluationblock.
un lucru care cred că ajută cu lizibilitate este de a plasa scriptblock în paranteze.
switch ( $age ){ ({$PSItem -le 18}) { 'child' } ({$PSItem -gt 18}) { 'adult' }}
se execută în același mod și oferă o pauză vizuală mai bună atunci când se uită rapid la ea.
Regex $se potrivește
trebuie să revizuim regex pentru a atinge ceva care nu este imediat evident. Utilizarea regexpopuleaza$matches
variabila . Eu merg în utilizarea $matches
mai mult atunci când vorbesc despremulte moduri de a utiliza regex. Aici este un eșantion rapid să-l arate în acțiune cu meciuri numite.
$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
puteți potrivi o $null
valoare care nu trebuie să fie implicit.
$value = $nullswitch ( $value ){ $null { 'Value is null' } default { 'value is not null' }}```OutputValue is null
același lucru este valabil pentru un șir gol.
switch ( '' ){ '' { 'Value is empty' } default { 'value is a empty string' }}```OutputValue is empty
expresie constantă
Lee Dailey a subliniat că putem folosi o constantă$true
Expresie pentru a evalua elemente.Imaginați-vă dacă avem mai multe verificări booleene care trebuie să se întâmple.
$isVisible = $false$isEnabled = $true$isSecure = $trueswitch ( $true ){ $isEnabled { 'Do-Action' } $isVisible { 'Show-Animation' } $isSecure { 'Enable-AdminMenu' }}
Do-ActionEnabled-AdminMenu
acesta este un mod curat de a evalua și de a lua măsuri cu privire la starea mai multor câmpuri booleene. Thecool lucru despre acest lucru este că puteți avea un meci flip starea unei valori care nu a fost încă evaluată.
$isVisible = $false$isEnabled = $true$isAdmin = $falseswitch ( $true ){ $isEnabled { 'Do-Action' $isVisible = $true } $isVisible { 'Show-Animation' } $isAdmin { 'Enable-AdminMenu' }}
Do-ActionShow-Animation
Setare $isEnabled
la $true
în acest exemplu se asigură că $isVisible
este de asemenea setat la$true
. Apoi, când $isVisible
este evaluat, scriptblock-ul său este invocat. Acesta este un bitcounter-intuitiv, dar este o utilizare inteligentă a mecanicii.
$switch automatic variable
cândswitch
își procesează valorile, creează un enumerator și îl numește$switch
. Aceasta esteo variabilă automată creată de PowerShell și o puteți manipula direct.
$a = 1, 2, 3, 4switch($a) { 1 { $switch.MoveNext(); $switch.Current } 3 { $switch.MoveNext(); $switch.Current }}
aceasta vă oferă rezultatele:
24
prin mutarea enumeratorului înainte, următorul element nu este procesat de switch
dar puteți accesa direct această valoare. Aș numi-o nebunie.
alte modele
Hashtables
una dintre cele mai populare postări ale mele este cea pe care am făcut-o pe hashtables. Unul dintre cazurile de utilizare pentru unhashtable
trebuie să fie un tabel de căutare. Aceasta este o abordare alternativă la un model comun pe care o declarațieswitch
se adresează adesea.
$day = 3$lookup = @{ 0 = 'Sunday' 1 = 'Monday' 2 = 'Tuesday' 3 = 'Wednesday' 4 = 'Thursday' 5 = 'Friday' 6 = 'Saturday'}$lookup
Wednesday
dacă folosesc doar un switch
ca Căutare, folosesc adesea un hashtable
în schimb.
Enum
PowerShell 5.0 a introdusEnum
și este, de asemenea, o opțiune în acest caz.
$day = 3enum DayOfTheWeek { Sunday Monday Tuesday Wednesday Thursday Friday Saturday}$day
Wednesday
am putea merge toată ziua în căutarea unor modalități diferite de a rezolva această problemă. Am vrut doar să mă asigur că știi că ai opțiuni.
cuvinte finale
instrucțiunea switch este simplă la suprafață, dar oferă câteva caracteristici avansate pe care majoritatea oamenilor nu le realizează sunt disponibile. Înșirarea acestor caracteristici împreună face ca aceasta să fie o caracteristică puternică. Sper că ai învățat ceva ce nu ți-ai dat seama până acum.