Articles

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 ComponentRole 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-Fileparameter. 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 Errore 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 switchque 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.

Deixe uma resposta

O seu endereço de email não será publicado. Campos obrigatórios marcados com *