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 istruzionielseif
eelse
. 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 Component
Role
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 cicloforeach
continue
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 Error
che 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 Error
cheWarning
, ma abbiamo solo bisogno di un processo. Questo è ciò che l’istruzione continue
sta facendo per noi.
Rompere etichette
Il switch
istruzione supporta break/continue
etichette 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 $true
per 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 switch
sta 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 unswitch
come 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.