Sdílet prostřednictvím


Všechno, co jste kdy chtěli vědět o příkazu switch

Stejně jako mnoho dalších jazyků má PowerShell příkazy pro řízení toku provádění ve vašich skriptech. Jedním z těchto příkazů je příkaz switch a v PowerShellu nabízí funkce, které nejsou nalezeny v jiných jazycích. Dnes se podrobně podíváme na práci s PowerShellem switch.

Poznámka:

původní verze tohoto článku se objevila na blogu napsaného @KevinMarquette. Tým PowerShellu děkujeme Kevinovi za sdílení tohoto obsahu s námi. Prosím, podívejte se na jeho blog na PowerShellExplained.com.

Příkaz if

Jedním z prvních příkazů, které se naučíte, je if příkaz. Umožňuje spustit blok skriptu, pokud je podmínka $true splněna.

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

Můžete mít mnohem složitější logiku pomocí příkazů elseif a else. Tady je příklad, kde mám číselnou hodnotu pro den v týdnu a chci získat název jako řetězec.

$day = 3

if ( $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

Ukázalo se, že se jedná o běžný vzor a existuje mnoho způsobů, jak to vyřešit. Jeden z nich je s switch.

příkaz switch

Příkaz switch umožňuje zadat proměnnou a seznam možných hodnot. Pokud se hodnota shoduje s proměnnou, spustí se její skriptblock.

$day = 3

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

$result
'Wednesday'

V tomto příkladu je hodnota $day shodná s jednou z číselných hodnot a pak je přiřazen $resultsprávný název . V tomto příkladu provádíme pouze přiřazení proměnné, ale v těchto blocích skriptu se dá spustit libovolný PowerShell.

Přiřaďte k proměnné

Tento poslední příklad můžeme napsat jiným způsobem.

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

Hodnotu umístíme do kanálu PowerShellu a přiřadíme ji k sadě $result. To samé můžete udělat s příkazy if a foreach.

Výchozí

Klíčové slovo můžeme použít default k identifikaci toho, co by se mělo stát, pokud neexistuje shoda.

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

Tady vrátíme hodnotu Unknown ve výchozím případě.

Řetězce

V posledních příkladech jsem shodovala čísla, ale můžete také shodovat řetězce.

$item = 'Role'

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

Rozhodl jsem se nezabalit shody Component, Role a Location do uvozovek, abych zdůraznil, že jsou volitelné. Ve většině případů s nimi switch zachází jako s řetězcem.

Pole

Jednou ze skvělých funkcí PowerShellu switch je způsob, jakým zpracovává pole. Pokud dáte switch pole, zpracuje každý prvek v této kolekci.

$roles = @('WEB','Database')

switch ( $roles ) {
    'Database'   { 'Configure SQL' }
    'WEB'        { 'Configure IIS' }
    'FileServer' { 'Configure Share' }
}
Configure IIS
Configure SQL

Pokud máte v poli opakující se položky, pak odpovídají příslušnému oddílu vícekrát.

PsItem

Můžete použít $PSItem nebo $_ odkazovat na aktuální položku, která byla zpracována. Když provedeme jednoduchou shodu, $PSItem je hodnota, kterou porovnáváme. Budu provádět několik pokročilých shod v další části, kde se tato proměnná používá.

Parametry

Jedinečnou funkcí PowerShellu switch je, že má řadu parametrů přepínače, které mění jeho výkon.

- Rozlišuje velká a malá písmena

Ve výchozím nastavení se shody nerozlišují malá a velká písmena. Pokud potřebujete rozlišovat malá a velká písmena, můžete použít -CaseSensitive. To lze použít v kombinaci s ostatními parametry přepínače.

-Zástupný znak

Pomocí přepínače -Wildcard můžeme povolit podporu zástupných znaků. Používá se stejná logika zástupných znaků, jakou používá operátor -like pro každou shodu.

$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

Tady zpracováváme zprávu a pak ji vypíšeme do různých datových proudů na základě obsahu.

-Regex

Příkaz switch podporuje shody regulárních výrazů stejně jako zástupné znaky.

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

Mám více příkladů použití regex v jiném článku jsem napsal: mnoho způsobů použití regex.

-Soubor

Trochu známou funkcí příkazu switch je, že může zpracovat soubor s parametrem -File . Místo toho, abyste mu dali proměnnou výraz, použijete -File cestu k souboru.

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

Funguje stejně jako zpracování pole. V tomto příkladu jej zkombinuji se zástupným znakem a použijem $PSItem. Tento postup zpracuje soubor protokolu a převede ho na upozornění a chybové zprávy v závislosti na shodě regulárních výrazů.

Pokročilé údaje

Teď, když víte o všech těchto dokumentovaných funkcích, je můžeme použít v kontextu pokročilejšího zpracování.

Výrazy

Může switch být ve výrazu místo proměnné.

switch ( ( Get-Service | where Status -EQ 'running' ).Name ) {...}

Cokoli, k čemu se výraz vyhodnotí, je hodnota použitá pro shodu.

Více shod

Možná jste si toho už postřehli, ale switch se může shodovat s několika podmínkami. To platí zejména při použití shod -Wildcard nebo -Regex. Stejnou podmínku můžete přidat vícekrát a všechny se aktivují.

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

Všechny tři tyto příkazy jsou ukončeny. To ukazuje, že každá podmínka je zkontrolována (v pořadí). To platí pro zpracování polí, kde každá položka kontroluje každou podmínku.

Pokračovat

Za normálních okolností je to místo, kde bych představil break prohlášení, ale je lepší, abychom se naučili, jak použít continue jako první. Stejně jako u foreach smyčky continue pokračuje na další položku v kolekci nebo ukončí switch , pokud už žádné další položky nejsou. Poslední příklad můžeme přepsat pomocí příkazů continue tak, aby se provedl pouze jeden příkaz.

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

Místo párování všech tří položek se první položka porovná a přepínač pokračuje k další hodnotě. Protože nejsou žádné hodnoty ke zpracování, přepínač skončí. Tento další příklad ukazuje, jak může zástupný znak odpovídat více položkám.

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

Vzhledem k tomu, že řádek ve vstupním souboru může obsahovat slovo Error i Warningslovo , chceme, aby se spustil pouze první řádek, a pak pokračovat ve zpracování souboru.

Přestávka

Příkaz break ukončí přepínač. Jedná se o stejné chování, které continue představuje pro jednotlivé hodnoty. Rozdíl se zobrazí při zpracování pole. break zastaví veškeré zpracování v přepínači a continue přesune se na další položku.

$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 update
WARNING: Ran into errors downloading file
Write-Error -Message $PSItem : Error: out of disk space
+ CategoryInfo          : NotSpecified: (:) [Write-Error], WriteErrorException
+ FullyQualifiedErrorId : Microsoft.PowerShell.Commands.WriteErrorException

Pokud v tomto případě narazíme na nějaké řádky, které začínají Error , zobrazí se chyba a přepínač se zastaví. Toto je to, co pro nás dělá ono tvrzení break. Pokud v řetězci najdeme Error nejen na začátku, napíšeme ho jako upozornění. Děláme to samé pro Warning. Je možné, že řádek může obsahovat slovo Error i Warning, ale potřebujeme pouze jedno ke zpracování. Toto pro nás dělá continue prohlášení.

Štítky přerušení

Příkaz switch podporuje break/continue popisky stejně jako 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
        }
    }
}

Osobně se mi nelíbí použití štítků přerušení, ale chtěl jsem na ně upozornit, protože mohou být matoucí, pokud jste se s nimi nikdy nesetkali. Pokud máte více switch příkazů nebo foreach příkazů, které jsou vnořené, můžete chtít vystoupit z více než jen z vnitřní položky. Můžete umístit popisek na switch, který může být cílem vašeho break.

Enum

PowerShell 5.0 nám poskytl výčty a můžeme je použít v přepínači.

enum Context {
    Component
    Role
    Location
}

$item = [Context]::Role

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

Pokud chcete zachovat vše jako výčty silného typu, můžete je umístit do závorek.

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

Tady jsou potřeba závorky, aby přepínač nezacházal s hodnotou [Context]::Location jako s literálovým řetězcem.

ScriptBlock

K vyhodnocení shody můžeme v případě potřeby použít skriptový blok.

$age = 37

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

To zvyšuje složitost a může ztížit čtení switch. Ve většině případů, kdy byste použili něco podobného, by bylo lepší použít if a elseif příkazy. Uvažoval bych o použití tohoto, pokud bych již měl velký přepínač a potřeboval jsem, aby se dvě položky dostaly do stejného hodnotícího bloku.

Jedna věc, která podle mě pomáhá s čitelností, je umístit blok skriptu do závorek.

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

Stále se provádí stejným způsobem a dává lepší vizuální přestávku, když se na ni rychle podíváte.

$Matches regulárních výrazů

Musíme se vrátit k regulárním výrazům, abychom se mohli dotknout něčeho, co není okamžitě zřejmé. Použití regexu plní proměnnou $Matches. Podrobněji se zabývám používáním $Matches, když mluvím o mnoha způsobech použití regulárních výrazů. Tady je rychlá ukázka, která ji zobrazí v akci s pojmenovanými shodami.

$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-3456
WARNING: message may contain a credit card number: 1234-5678-1234-5678

$null

Můžete se shodovat s $null hodnotou, která nemusí být výchozí.

$values = '', 5, $null
switch ( $values )
{
    $null          { "Value '$_' is `$null" }
    { '' -eq $_ }  { "Value '$_' is an empty string" }
    default        { "Value [$_] isn't an empty string or `$null" }
}
Value '' is an empty string
Value [5] isn't an empty string or $null
Value '' is $null

Při testování prázdného řetězce v switch příkazu je důležité použít příkaz porovnání, jak je znázorněno v tomto příkladu místo nezpracované hodnoty ''. V příkazu se nezpracovaná switch hodnota '' také shoduje $null. Například:

$values = '', 5, $null
switch ( $values )
{
    $null          { "Value '$_' is `$null" }
    ''             { "Value '$_' is an empty string" }
    default        { "Value [$_] isn't an empty string or `$null" }
}
Value '' is an empty string
Value [5] isn't an empty string or $null
Value '' is $null
Value '' is an empty string

Také buďte opatrní s prázdnými výstupy z cmdletů. Cmdlety nebo kanály, které nemají žádný výstup, se považují za prázdné pole, které neodpovídá ničemu, včetně případu default.

$file = Get-ChildItem NonExistantFile*
switch ( $file )
{
    $null   { '$file is $null' }
    default { "`$file is type $($file.GetType().Name)" }
}
# No matches

Konstantní výraz

Lee Dailey zdůraznil, že k vyhodnocení [bool] položek můžeme použít konstantní $true výraz. Představte si, že máme několik logických kontrol, ke kterým musí dojít.

$isVisible = $false
$isEnabled = $true
$isSecure = $true

switch ( $true )
{
    $isEnabled
    {
        'Do-Action'
    }
    $isVisible
    {
        'Show-Animation'
    }
    $isSecure
    {
        'Enable-AdminMenu'
    }
}
Do-Action
Enabled-AdminMenu

Toto je elegantní způsob, jak vyhodnotit a jednat ohledně stavu několika logických polí. Skvělé na tom je, že můžete mít jednu operaci, která překlopí stav hodnoty, jež ještě nebyla vyhodnocena.

$isVisible = $false
$isEnabled = $true
$isAdmin = $false

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

Nastavení $isEnabled v $true tomto příkladu zajistí, že $isVisible je také nastavena na $true. Poté, když je $isVisible vyhodnoceno, pak se vyvolá jeho skriptový blok. To je trochu protiintuitivní, ale je to chytrý způsob použití mechaniky.

$switch automatické proměnné

switch Při zpracování svých hodnot vytvoří enumerátor a zavolá ho $switch. Jedná se o automatickou proměnnou vytvořenou prostředím PowerShell a můžete s ní pracovat přímo.

$a = 1, 2, 3, 4

switch($a) {
    1 { [void]$switch.MoveNext(); $switch.Current }
    3 { [void]$switch.MoveNext(); $switch.Current }
}

Tím získáte výsledky:

2
4

Přesunutím enumerátoru dopředu se další položka nezpracuje pomocí switch, ale k této hodnotě se můžete dostat přímo. Říkal bych to šílenství.

Jiné vzory

Hashtables

Jedním z mých nejoblíbenějších příspěvků je ten, který jsem udělal na hashtables. Jedním z případů použití hashtable je vyhledávací tabulka. Jedná se o alternativní přístup k běžnému vzoru, který switch příkaz často řeší.

$day = 3

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

$lookup[$day]
Wednesday

Pokud používám switch pouze pro vyhledávání, často používám místo toho hashtable.

Enum

PowerShell 5.0 představil enum a v tomto případě je to také možnost.

$day = 3

enum DayOfTheWeek {
    Sunday
    Monday
    Tuesday
    Wednesday
    Thursday
    Friday
    Saturday
}

[DayOfTheWeek]$day
Wednesday

Celý den bychom se mohli podívat na různé způsoby, jak tento problém vyřešit. Jen jsem se chtěl ujistit, že jsi věděl, že máš možnosti.

Konečná slova

Příkaz switch je na povrchu jednoduchý, ale nabízí některé pokročilé funkce, o kterých většina lidí ani netuší, že jsou k dispozici. Propojení těchto funkcí dohromady činí z toho silnou funkci. Doufám, že jste se dozvěděli něco, co jste si předtím neuvědomili.