Articles

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 ComponentRole ș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 switchcare 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.

Lasă un răspuns

Adresa ta de email nu va fi publicată. Câmpurile obligatorii sunt marcate cu *