Tudo o que você sempre quis saber sobre a instrução switch
- 03/01/2021
- 12 minutos para ler
-
- s
- c
- x
Como muitas outras línguas, o PowerShell possui comandos para controlar o fluxo de execução dentro yourscripts. Uma dessas afirmações é a declaração switch e, em PowerShell, oferece façanhas que não são encontradas em outras línguas. Hoje, mergulhamos profundamente em trabalhar com o PowerShellswitch
.
Nota
a versão original deste artigo apareceu no blog escrito por @KevinMarquette. A equipa de showershell agradece ao Kevin por partilhar este conteúdo connosco. Por favor, confira seu blog atPowerShellExplained.com.
a declaração de fi
uma das primeiras afirmações que você aprende é a declaração deif
. Permite-lhe executar um script blockif uma instrução é $true
.
if ( Test-Path $Path ){ Remove-Item $Path}
Você pode ter muito mais complicado lógica usando elseif
e else
instruções. Aqui está um exemplo onde eu tenho um valor numérico para o dia da semana e eu quero obter o nome como uma string.
$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
acontece que este é um padrão comum, e há muitas maneiras de lidar com isso. Um deles é com um switch
.
Switch statement
The switch
statement allows you to provide a variable and a list of possible values. Se o valor faz a variável, então seu scriptblock é executado.
$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'
neste exemplo, o valor de $day
corresponde a um dos valores numéricos, em seguida, o nome correto isassigned para $result
. Estamos apenas fazendo uma atribuição variável neste exemplo, mas qualquer PowerShell pode ser executada nesses blocos de script.
atribuir a uma variável
podemos escrever esse último exemplo de outra forma.
$result = switch ( $day ){ 0 { 'Sunday' } 1 { 'Monday' } 2 { 'Tuesday' } 3 { 'Wednesday' } 4 { 'Thursday' } 5 { 'Friday' } 6 { 'Saturday' }}
we are placing the value on the PowerShell pipeline and assigning it to the $result
. Você pode fazer a mesma coisa com as declarações if
e foreach
.
Default
We can use the default
keyword to identify the what should happen if there is no match.
$result = switch ( $day ){ 0 { 'Sunday' } # ... 6 { 'Saturday' } default { 'Unknown' }}
Aqui devolvemos o valorUnknown
no caso predefinido.
Strings
I estava combinando números nesses últimos exemplos, mas você também pode combinar strings.
$item = 'Role'switch ( $item ){ Component { 'is a component' } Role { 'is a role' } Location { 'is a location' }}
is a role
eu decidi não quebrar o Component
Role
e Location
correspondências entre aspas aqui destacar thatthey são opcionais. O switch
trata-os como uma cadeia na maioria dos casos.
Arrays
uma das características legais da PowerShell switch
é a forma como lida com arrays. Se você der umswitch
um array, ele processa cada elemento nessa coleção.
$roles = @('WEB','Database')switch ( $roles ) { 'Database' { 'Configure SQL' } 'WEB' { 'Configure IIS' } 'FileServer' { 'Configure Share' }}
Configure IISConfigure SQL
PSItem
Você pode usar o $PSItem
ou $_
para referenciar o item atual que foi processado. Quando fazemos asimple match, $PSItem
é o valor que estamos combinando. Vou fazer algumas combinações avançadas na próxima secção onde esta variável é usada.
Parameters
a unique feature of the PowerShell switch
is that it has a number of switch parameters thatchange how it performs.
-CaseSensitive
as correspondências não são sensíveis à capitalização por omissão. Se precisar de ser sensível à capitalização, pode usar-CaseSensitive
. Isto pode ser usado em combinação com os outros parâmetros do interruptor.
– Wildcard
podemos activar o Suporte de caracteres especiais com o -wildcard
switch. Isto usa a mesma lógica de caracteres especiais que o-like
operador para fazer cada correspondência.
$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
Aqui estamos nós de processamento de uma mensagem e, em seguida, saída em diferentes fluxos com base no conteúdo.
– Regex
a declaração de switch suporta correspondências regex tal como faz com os caracteres especiais.
switch -Regex ( $message ){ '^Error' { Write-Error -Message $Message } '^Warning' { Write-Warning -Message $Message } default { Write-Information $message }}
i have more examples of using regex in another article I wrote: The many ways to use regex.
– File
a little known feature of the switch statement is that it can process a file with the-File
parameter. Você usa -file
com um caminho para um arquivo em vez de dar-lhe uma expressão variável.
switch -Wildcard -File $path{ 'Error*' { Write-Error -Message $PSItem } 'Warning*' { Write-Warning -Message $PSItem } default { Write-Output $PSItem }}
ele funciona assim como processar um array. Neste exemplo, combino-o com a correspondência de caracteres especiais e faço uso do $PSItem
. Isto processaria um ficheiro de registo e convertê-lo-ia em avisos e mensagens de erro, dependendo das correspondências regex.
detalhes avançados
Agora que você está ciente de todas essas características documentadas, podemos usá-los no contexto de processamento mais avançado.
expressões
o switch
pode estar numa expressão em vez de uma variável.
switch ( ( Get-Service | Where status -eq 'running' ).name ) {...}
qualquer que seja a expressão avaliada como sendo o valor usado para a correspondência.
várias ocorrências
pode já ter percebido isto, mas uma switch
pode corresponder a várias condições. Isto é especialmente verdadeiro quando se usa -wildcard
ou -regex
matches. Você pode adicionar a mesma condição multiplezes e todos eles são acionados.
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
todas as três afirmações são disparadas. Isto mostra que todas as condições são verificadas (por ordem). Estas inscrições são verdadeiras para processamento de arrays onde cada item verifica cada condição.
Continue
normalmente, é aqui que eu introduziria a declaraçãobreak
, mas é melhor que aprendamos como usarcontinue
primeiro. Assim como com um foreach
loop, continue
continua no próximo item da colecção ou sai do switch
se não houver mais itens. Podemos reescrever o último exemplo com declarações Continuar para que apenas uma declaração execute.
switch ( 'Word' ){ 'word' { 'lower case word match' continue } 'Word' { 'mixed case word match' continue } 'WORD' { 'upper case word match' continue }}
lower case word match
em Vez de correspondência a todos os três itens, o primeiro é correspondido e o interruptor continua a nextvalue. Como não há mais valores para processar, a troca sai. Este próximo exemplo é mostrar como uma carta especial pode corresponder a vários itens.
switch -Wildcard -File $path{ '*Error*' { Write-Error -Message $PSItem continue } '*Warning*' { Write-Warning -Message $PSItem continue } default { Write-Output $PSItem }}
Devido a uma linha no arquivo de entrada pode conter tanto a palavra Error
e Warning
, queremos apenas oprimeiro um para executar e, em seguida, continuar com o processamento do arquivo.
quebra
a break
a declaração sai do interruptor. Este é o mesmo comportamento que continue
apresenta para valores únicos. A diferença é mostrada ao processar um array. break
pára todo o processamento na comutação e continue
passa para o próximo item.
$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
neste caso, se acertar todas as linhas que começam com Error
, em seguida, recebemos um erro e o interruptor pára.Isto é o que a afirmação break
está fazendo por nós. Se encontrarmos Error
dentro da string e não apenas no início, nós a escrevemos como um aviso. Nós fazemos a mesma coisa para Warning
. É possível que uma linha possa ter tanto a palavra Error
e Warning
, mas só precisamos de um processo. Isto é o que a declaração continue
está fazendo por nós.
Break labels
The switch
statement supportsbreak/continue
labels just likeforeach
.
: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 } }}
pessoalmente não gosto do uso de etiquetas de quebra, mas eu queria apontá-las porque elas estão a funcionar se você nunca as viu antes. Quando você tem vários switch
ou foreach
estatamentos que estão aninhados, você pode querer sair de mais do que o item mais interno. Você pode colocar um labelon a switch
que pode ser o alvo do seu.
Enum
PowerShell 5.0 deu-nos enums e podemos usá-los num interruptor.
enum Context { Component Role Location}$item = ::Roleswitch ( $item ){ Component { 'is a component' } Role { 'is a role' } Location { 'is a location' }}
is a role
Se quiser manter tudo tão fortemente tipado enums, então poderá colocá-los entre parêntesis.
switch ($item ){ (::Component) { 'is a component' } (::Role) { 'is a role' } (::Location) { 'is a location' }}
os parêntesis são necessários aqui para que o interruptor não trate o valor ::Location
como texto literal.
ScriptBlock
podemos usar um scriptblock para realizar a avaliação de uma partida, se necessário.
$age = 37switch ( $age ){ {$PSItem -le 18} { 'child' } {$PSItem -gt 18} { 'adult' }}
'adult'
Isto aumenta a complexidade e pode fazer o seu switch
difícil de ler. Na maioria dos casos em que você usaria algo assim, seria melhor usar declarações if
e elseif
. Eu consideraria usar isso se eu já tivesse uma grande mudança no lugar e eu precisava de dois itens para atingir o mesmo bloqueio de avaliação.
uma coisa que eu acho que ajuda com a legibilidade é colocar o scriptblock entre parênteses.
switch ( $age ){ ({$PSItem -le 18}) { 'child' } ({$PSItem -gt 18}) { 'adult' }}
ele ainda executa da mesma forma e dá uma melhor pausa visual ao olhar rapidamente para ele.
Regex $corresponde a
precisamos revisitar regex para tocar em algo que não é imediatamente óbvio. The use of regexpopulates the $matches
variable. I do go into the use of $matches
more when I talk about the many ways to use regex. Aqui está uma amostra rápida para mostrá-lo em ação com fósforos nomeados.
$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
Você pode combinar uma $null
valor que não tem que ser o padrão.
$value = $nullswitch ( $value ){ $null { 'Value is null' } default { 'value is not null' }}```OutputValue is null
Same goes for an empty string.
switch ( '' ){ '' { 'Value is empty' } default { 'value is a empty string' }}```OutputValue is empty
expressão Constante
Lee Dailey apontou que podemos usar uma constante $true
expressão para avaliar itens.Imagine se tivermos vários controlos booleanos que precisam de acontecer.
$isVisible = $false$isEnabled = $true$isSecure = $trueswitch ( $true ){ $isEnabled { 'Do-Action' } $isVisible { 'Show-Animation' } $isSecure { 'Enable-AdminMenu' }}
Do-ActionEnabled-AdminMenu
esta é uma forma limpa de avaliar e tomar medidas sobre o estado de vários campos booleanos. A coisa cool sobre isso é que você pode ter uma correspondência inverter o status de um valor que ainda não foi avaliado.
$isVisible = $false$isEnabled = $true$isAdmin = $falseswitch ( $true ){ $isEnabled { 'Do-Action' $isVisible = $true } $isVisible { 'Show-Animation' } $isAdmin { 'Enable-AdminMenu' }}
Do-ActionShow-Animation
Definição $isEnabled
$true
neste exemplo, torna-se de que $isVisible
também está definido para$true
. Então quando $isVisible
é avaliado, seu scriptblock é invocado. Este é um bitcounter-intuitivo, mas é um uso inteligente da mecânica.
$switch automatic variable
When the switch
is processing its values, it creates an enumerator and calls it $switch
. Esta é uma variável automática criada pela PowerShell e você pode manipulá-la diretamente.
$a = 1, 2, 3, 4switch($a) { 1 { $switch.MoveNext(); $switch.Current } 3 { $switch.MoveNext(); $switch.Current }}
Isso dá a você os resultados de:
24
Ao mover o enumerador para a frente, o próximo item não serem processados pelo switch
mas você canaccess que o valor diretamente. Chamar-lhe-ia loucura.
outros padrões
Hashtables
um dos meus posts mais populares é o que eu fiz em hashtables. Um dos casos de uso para um hashtable
é ser uma tabela de pesquisa. Esta é uma abordagem alternativa a um padrão comum que uma declaraçãoswitch
é frequentemente abordada.
$day = 3$lookup = @{ 0 = 'Sunday' 1 = 'Monday' 2 = 'Tuesday' 3 = 'Wednesday' 4 = 'Thursday' 5 = 'Friday' 6 = 'Saturday'}$lookup
Wednesday
Se eu estou usando somente um switch
como uma pesquisa, eu sempre uso um hashtable
em vez disso.
Enum
PowerShell 5.0 introduziu o Enum
e é também uma opção neste caso.
$day = 3enum DayOfTheWeek { Sunday Monday Tuesday Wednesday Thursday Friday Saturday}$day
Wednesday
podíamos passar o dia a procurar diferentes formas de resolver este problema. Só queria ter a certeza que sabias que tinhas opções.
palavras finais
a declaração de switch é simples na superfície, mas oferece algumas características avançadas que a maioria das pessoas não percebem estão disponíveis. Juntar essas características torna esta uma característica poderosa. Espero que tenhas aprendido algo que não tinhas percebido antes.