Articles

Tutto quello che avete sempre voluto sapere sull’istruzione switch

  • 03/01/2021
  • 12 minuti a leggere
    • c
    • x

Come molti altri linguaggi, PowerShell ha i comandi per controllare il flusso di esecuzione all’interno di yourscripts. Una di queste dichiarazioni è l’istruzione switch e in PowerShell, offre funzionalità che non si trovano in altre lingue. Oggi, facciamo un tuffo profondo nel lavoro con PowerShellswitch.

Nota

La versione originale di questo articolo è apparso sul blog scritto da @KevinMarquette. Il team di PowerShell ringrazia Kevin per aver condiviso questo contenuto con noi. Si prega di controllare il suo blog atPowerShellExplained.com.

L’istruzione if

Una delle prime istruzioni che si impara è l’istruzione if. Consente di eseguire un blocco di script se un’istruzione è $true.

if ( Test-Path $Path ){ Remove-Item $Path}

Puoi avere una logica molto più complicata usando le istruzionielseifeelse. Ecco un esempio in cui ho un valore numerico per il giorno della settimana e voglio ottenere il nome come stringa.

$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

Si scopre che questo è un modello comune e ci sono molti modi per affrontarlo. Uno di essi è con unswitch.

Istruzione switch

L’istruzioneswitch consente di fornire una variabile e un elenco di valori possibili. Se il valuematches la variabile, quindi il suo scriptblock viene eseguito.

$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'

Per questo esempio, il valore di $day corrisponde a uno dei valori numerici, quindi il nome corretto isassigned $result. Stiamo solo facendo un’assegnazione variabile in questo esempio, ma qualsiasi PowerShellpuò essere eseguito in quei blocchi di script.

Assegna a una variabile

Possiamo scrivere quell’ultimo esempio in un altro modo.

$result = switch ( $day ){ 0 { 'Sunday' } 1 { 'Monday' } 2 { 'Tuesday' } 3 { 'Wednesday' } 4 { 'Thursday' } 5 { 'Friday' } 6 { 'Saturday' }}

Stiamo posizionando il valore sulla pipeline PowerShell e assegnandolo al$result. Puoi fare la stessa cosa con le istruzioni if e foreach.

Default

Possiamo usare la parola chiavedefault per identificare cosa dovrebbe accadere se non c’è corrispondenza.

$result = switch ( $day ){ 0 { 'Sunday' } # ... 6 { 'Saturday' } default { 'Unknown' }}

Qui restituiamo il valoreUnknown nel caso predefinito.

Strings

Stavo abbinando i numeri in questi ultimi esempi, ma puoi anche abbinare le stringhe.

$item = 'Role'switch ( $item ){ Component { 'is a component' } Role { 'is a role' } Location { 'is a location' }}
is a role

ho deciso di non avvolgere il ComponentRole e Location confronta i preventivi per evidenziare thatthey facoltativi. Il switch tratta quelli come una stringa nella maggior parte dei casi.

Array

Una delle caratteristiche interessanti di PowerShellswitch è il modo in cui gestisce gli array. Se si fornisce unswitch un array, elabora ogni elemento in quella raccolta.

$roles = @('WEB','Database')switch ( $roles ) { 'Database' { 'Configure SQL' } 'WEB' { 'Configure IIS' } 'FileServer' { 'Configure Share' }}
Configure IISConfigure SQL

Se si hanno elementi ripetuti nel proprio array, vengono abbinati più volte dalla sezione appropriata.

PSItem

È possibile utilizzare$PSItem o$_ per fare riferimento all’elemento corrente che è stato elaborato. Quando facciamo una semplice corrispondenza, $PSItem è il valore che stiamo corrispondendo. Eseguirò alcune partite avanzate nella prossima sezione in cui viene utilizzata questa variabile.

Parametri

Una caratteristica unica di PowerShellswitch è che ha un numero di parametri di commutazionecambia come si comporta.

-CaseSensitive

Le corrispondenze non sono case-sensitive per impostazione predefinita. Se è necessario essere case-sensitive, è possibile utilizzare -CaseSensitive. Questo può essere utilizzato in combinazione con gli altri parametri dell’interruttore.

-Jolly

Possiamo abilitare il supporto jolly con l’interruttore-wildcard. Questo utilizza la stessa logica jolly dell’operatore-like per eseguire ogni corrispondenza.

$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

Qui stiamo elaborando un messaggio e quindi emettendolo su diversi flussi in base al contenuto.

-Regex

L’istruzione switch supporta le corrispondenze regex proprio come fa con i caratteri jolly.

switch -Regex ( $message ){ '^Error' { Write-Error -Message $Message } '^Warning' { Write-Warning -Message $Message } default { Write-Information $message }}

Ho altri esempi di utilizzo di regex in un altro articolo che ho scritto: I molti modi per usare regex.

-File

Una caratteristica poco nota dell’istruzione switch è che può elaborare un file con il parametro-File. Si utilizza-file con un percorso di un file invece di dargli un’espressione variabile.

switch -Wildcard -File $path{ 'Error*' { Write-Error -Message $PSItem } 'Warning*' { Write-Warning -Message $PSItem } default { Write-Output $PSItem }}

Funziona proprio come l’elaborazione di un array. In questo esempio, lo combino con la corrispondenza dei caratteri jolly e uso $PSItem. Ciò elaborerebbe un file di registro e lo convertirebbe in warning e errormessages a seconda delle corrispondenze regex.

Dettagli avanzati

Ora che sei a conoscenza di tutte queste funzionalità documentate, possiamo utilizzarle nel contesto di un’elaborazione più avanzata.

Espressioni

Ilswitch può essere su un’espressione invece di una variabile.

switch ( ( Get-Service | Where status -eq 'running' ).name ) {...}

Qualunque sia l’espressione valutata è il valore utilizzato per la corrispondenza.

Corrispondenze multiple

Potresti aver già rilevato questo, ma unswitch può corrispondere a più condizioni. Ciò è particolarmente vero quando si utilizzano-wildcard o-regex corrispondenze. È possibile aggiungere la stessa condizione più volte e tutti sono attivati.

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

Tutte e tre queste istruzioni vengono attivate. Questo dimostra che ogni condizione è controllata (in ordine). Thisholds true per l’elaborazione di array in cui ogni elemento controlla ogni condizione.

Continua

Normalmente, è qui che introdurrei l’istruzione break, ma è meglio imparare comeusare prima continue. Proprio come con un cicloforeachcontinue continua sull’elemento successivo nella raccolta o esce daswitch se non ci sono più elementi. Possiamo riscrivere l’ultimo esempio con le istruzioni continue in modo che venga eseguita solo un’istruzione.

switch ( 'Word' ){ 'word' { 'lower case word match' continue } 'Word' { 'mixed case word match' continue } 'WORD' { 'upper case word match' continue }}
lower case word match

Invece di abbinare tutti e tre gli elementi, il primo viene abbinato e l’interruttore continua al valore successivo. Poiché non ci sono valori da elaborare, l’interruttore esce. Questo prossimo esempio mostra come un carattere jolly potrebbe corrispondere a più elementi.

switch -Wildcard -File $path{ '*Error*' { Write-Error -Message $PSItem continue } '*Warning*' { Write-Warning -Message $PSItem continue } default { Write-Output $PSItem }}

Poiché una riga nel file di input potrebbe contenere sia la parola Errorche Warning, vogliamo solo che il primo venga eseguito e quindi continui l’elaborazione del file.

Break

Abreak esce dall’interruttore. Questo è lo stesso comportamento checontinue presenta per singlevalues. La differenza viene mostrata durante l’elaborazione di un array. break interrompe tutta l’elaborazione nello switchandcontinue passa all’elemento successivo.

$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

In questo caso, se colpiamo qualsiasi riga che inizia conError, otteniamo un errore e l’interruttore si arresta.Questo è ciò che l’istruzionebreak sta facendo per noi. Se troviamo Error all’interno della stringa e notjust all’inizio, lo scriviamo come un avvertimento. Facciamo la stessa cosa per Warning. È possibile che una riga possa avere sia la parola ErrorcheWarning, ma abbiamo solo bisogno di un processo. Questo è ciò che l’istruzione continue sta facendo per noi.

Rompere etichette

Il switch istruzione supporta break/continueetichette proprio come 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 } }}

Personalmente non mi piace l’uso delle etichette di interruzione, ma volevo segnalarle perché si stanno confondendo se non le hai mai viste prima. Quando hai piùswitch oforeach statementsthat sono annidati, potresti voler uscire da più elementi interni. Puoi inserire un’etichetta in unswitch che può essere il target del tuobreak.

Enum

PowerShell 5.0 ci ha dato enum e possiamo usarli in un interruttore.

enum Context { Component Role Location}$item = ::Roleswitch ( $item ){ Component { 'is a component' } Role { 'is a role' } Location { 'is a location' }}
is a role

Se si desidera mantenere tutto come enumerazioni fortemente digitate, è possibile inserirle tra parentesi.

switch ($item ){ (::Component) { 'is a component' } (::Role) { 'is a role' } (::Location) { 'is a location' }}

Le parentesi sono necessarie qui in modo che lo switch non tratti il valore::Location asa stringa letterale.

ScriptBlock

Possiamo usare uno scriptblock per eseguire la valutazione di una partita, se necessario.

$age = 37switch ( $age ){ {$PSItem -le 18} { 'child' } {$PSItem -gt 18} { 'adult' }}
'adult'

Questo aggiunge complessità e può rendere il tuoswitch difficile da leggere. Nella maggior parte dei casi in cui usereste qualcosa di simile sarebbe meglio usare if e elseif istruzioni. Prenderei in considerazione l’utilizzo di questo se avessi già un interruttore di grandi dimensioni e avevo bisogno di due elementi per colpire lo stesso evaluationblock.

Una cosa che penso aiuti con la leggibilità è mettere lo scriptblock tra parentesi.

switch ( $age ){ ({$PSItem -le 18}) { 'child' } ({$PSItem -gt 18}) { 'adult' }}

Si esegue ancora allo stesso modo e dà una migliore pausa visiva quando lo si guarda rapidamente.

Regex matches corrisponde a

Dobbiamo rivisitare regex per toccare qualcosa che non è immediatamente ovvio. L’uso di regexpopula la variabile$matches. Vado nell’uso di $matches di più quando parlo di molti modi per usare regex. Ecco un esempio rapido per mostrarlo in azione con corrispondenze denominate.

$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 null

È possibile abbinare un valore$null che non deve essere il valore predefinito.

$value = $nullswitch ( $value ){ $null { 'Value is null' } default { 'value is not null' }}```OutputValue is null

Lo stesso vale per una stringa vuota.

switch ( '' ){ '' { 'Value is empty' } default { 'value is a empty string' }}```OutputValue is empty

Espressione costante

Lee Dailey ha sottolineato che possiamo usare un’espressione costante $trueper valutare elementi.Immagina se abbiamo diversi controlli booleani che devono accadere.

$isVisible = $false$isEnabled = $true$isSecure = $trueswitch ( $true ){ $isEnabled { 'Do-Action' } $isVisible { 'Show-Animation' } $isSecure { 'Enable-AdminMenu' }}
Do-ActionEnabled-AdminMenu

Questo è un modo pulito per valutare e agire sullo stato di diversi campi booleani. Thecool cosa su questo è che si può avere una partita capovolgere lo stato di un valore che non è stato ancora valutato.

$isVisible = $false$isEnabled = $true$isAdmin = $falseswitch ( $true ){ $isEnabled { 'Do-Action' $isVisible = $true } $isVisible { 'Show-Animation' } $isAdmin { 'Enable-AdminMenu' }}
Do-ActionShow-Animation

Regolazione $isEnabled$true in questo esempio fa in modo che il $isVisible è impostato su$true. Quindi quando$isVisible viene valutato, viene invocato il suo scriptblock. Questo è un bitcounter-intuitivo ma è un uso intelligente della meccanica.

switch cambia variabile automatica

Quando il switchsta elaborando i suoi valori, crea un enumeratore e lo chiama $switch. Questa è una variabile automatica creata da PowerShell e puoi manipolarla direttamente.

$a = 1, 2, 3, 4switch($a) { 1 { $switch.MoveNext(); $switch.Current } 3 { $switch.MoveNext(); $switch.Current }}

Questo ti dà i risultati di:

24

Spostando l’enumeratore in avanti, l’elemento successivo non viene elaborato daswitch ma puoi accedere direttamente a quel valore. La chiamerei follia.

Altri modelli

Hashtables

Uno dei miei post più popolari è quello che ho fatto su hashtables. Uno dei casi d’uso per unhashtable deve essere una tabella di ricerca. Questo è un approccio alternativo a un modello comune che un’istruzioneswitch viene spesso indirizzata.

$day = 3$lookup = @{ 0 = 'Sunday' 1 = 'Monday' 2 = 'Tuesday' 3 = 'Wednesday' 4 = 'Thursday' 5 = 'Friday' 6 = 'Saturday'}$lookup
Wednesday

Se sto usando solo unswitchcome ricerca, uso spesso unhashtable.

Enum

PowerShell 5.0 ha introdotto ilEnum ed è anche un’opzione in questo caso.

$day = 3enum DayOfTheWeek { Sunday Monday Tuesday Wednesday Thursday Friday Saturday}$day
Wednesday

Potremmo andare tutto il giorno a cercare diversi modi per risolvere questo problema. Volevo solo assicurarmi che sapessi che avevi delle opzioni.

Parole finali

L’istruzione switch è semplice in superficie ma offre alcune funzionalità avanzate che la maggior parte delle persone non si rende conto sono disponibili. Mettere insieme queste caratteristiche rende questa una caratteristica potente. Spero che tu abbia imparato qualcosa che non avevi capito prima.

Lascia un commento

Il tuo indirizzo email non sarà pubblicato. I campi obbligatori sono contrassegnati *