Semua yang anda inginkan untuk mengetahui tentang pernyataan switch

Seperti banyak bahasa lain, PowerShell memiliki perintah untuk mengontrol alur eksekusi dalam skrip Anda. Salah satu pernyataan tersebut adalah pernyataan pengalihan dan di PowerShell, ia menawarkan fitur yang tidak ditemukan dalam bahasa lain. Hari ini, kami menyelam lebih dalam untuk bekerja dengan PowerShell switch.

Catatan

Versi asli artikel ini muncul di blog yang ditulis oleh @KevinMarquette. Tim PowerShell berterima kasih kepada Kevin karena telah membagikan konten ini kepada kami. Silakan lihat blognya di PowerShellExplained.com.

Pernyataan if

Salah satu pernyataan pertama yang Anda pelajari adalah pernyataan .if Ini memungkinkan Anda menjalankan blok skrip jika pernyataan adalah $true.

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

Anda dapat memiliki logika yang jauh lebih rumit menggunakan elseif pernyataan dan else . Berikut adalah contoh di mana saya memiliki nilai numerik untuk hari dalam seminggu dan saya ingin mendapatkan nama sebagai string.

$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

Ternyata ini adalah pola umum dan ada banyak cara untuk menangani hal ini. Salah satunya adalah dengan switch.

Pernyataan beralih

Pernyataan ini switch memungkinkan Anda untuk memberikan variabel dan daftar nilai yang mungkin. Jika nilai cocok dengan variabel, maka blok skripnya dijalankan.

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

Untuk contoh ini, nilai cocok dengan $day salah satu nilai numerik, maka nama yang benar ditetapkan ke $result. Kami hanya melakukan penetapan variabel dalam contoh ini, tetapi PowerShell apa pun dapat dijalankan di blok skrip tersebut.

Menetapkan ke variabel

Kita dapat menulis contoh terakhir dengan cara lain.

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

Kami menempatkan nilai pada alur PowerShell dan menetapkannya ke $result. Anda dapat melakukan hal yang sama dengan if pernyataan dan foreach .

Default

Kita dapat menggunakan default kata kunci untuk mengidentifikasi apa yang harus terjadi jika tidak ada kecocokan.

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

Di sini kita mengembalikan nilai Unknown dalam kasus default.

String

Saya mencocokkan angka dalam contoh terakhir, tetapi Anda juga dapat mencocokkan string.

$item = 'Role'

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

Saya memutuskan untuk tidak membungkus Component,Role dan Location cocok dalam tanda kutip di sini untuk menyoroti bahwa mereka opsional. memperlakukan switch mereka sebagai string dalam banyak kasus.

Larik

Salah satu fitur keren PowerShell switch adalah caranya menangani array. Jika Anda memberikan switch array, ia memproses setiap elemen dalam koleksi tersebut.

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

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

Jika Anda memiliki item berulang dalam array Anda, maka item tersebut dicocokkan beberapa kali oleh bagian yang sesuai.

PSItem

Anda dapat menggunakan $PSItem atau $_ untuk mereferensikan item saat ini yang diproses. Ketika kita melakukan kecocokan sederhana, $PSItem adalah nilai yang kita cocokkan. Saya akan melakukan beberapa kecocokan lanjutan di bagian berikutnya tempat variabel ini digunakan.

Parameter

Fitur unik PowerShell adalah powerShell switch memiliki sejumlah parameter pengalihan yang mengubah performanya.

-CaseSensitive

Kecocokan tidak peka huruf besar/kecil secara default. Jika Anda perlu peka huruf besar/kecil, Anda dapat menggunakan -CaseSensitive. Ini dapat digunakan dalam kombinasi dengan parameter sakelar lainnya.

-Kartubebas

Kita dapat mengaktifkan dukungan kartubebas dengan sakelar -wildcard . Ini menggunakan logika wildcard yang sama dengan -like operator untuk melakukan setiap kecocokan.

$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

Di sini kami memproses pesan lalu mengeluarkannya pada aliran yang berbeda berdasarkan konten.

-Regex

Pernyataan switch mendukung kecocokan regex sama seperti wildcard.

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

Saya memiliki lebih banyak contoh penggunaan regex di artikel lain yang saya tulis: Banyak cara untuk menggunakan regex.

-File

Fitur yang sedikit diketahui dari pernyataan pengalihan adalah dapat memproses file dengan -File parameter . Anda menggunakan -file dengan jalur ke file alih-alih memberinya ekspresi variabel.

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

Ini berfungsi seperti memproses array. Dalam contoh ini, saya menggabungkannya dengan pencocokan kartubebas dan memanfaatkan $PSItem. Ini akan memproses file log dan mengonversinya menjadi pesan peringatan dan kesalahan tergantung pada kecocokan regex.

Detail tingkat lanjut

Sekarang setelah Anda mengetahui semua fitur yang didokumentasikan ini, kita dapat menggunakannya dalam konteks pemrosesan yang lebih canggih.

Expressions

switch dapat berada pada ekspresi alih-alih variabel.

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

Apa pun yang dievaluasi oleh ekspresi adalah nilai yang digunakan untuk kecocokan.

Beberapa kecocokan

Anda mungkin telah mengambil ini, tetapi switch dapat cocok dengan beberapa kondisi. Ini terutama berlaku saat menggunakan -wildcard atau -regex mencocokkan. Anda dapat menambahkan kondisi yang sama beberapa kali dan semuanya dipicu.

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

Ketiga pernyataan ini dipecat. Ini menunjukkan bahwa setiap kondisi diperiksa (secara berurutan). Ini berlaku untuk memproses array di mana setiap item memeriksa setiap kondisi.

Lanjutkan

Biasanya, di sinilah saya akan memperkenalkan break pernyataan, tetapi lebih baik kita belajar cara menggunakannya continue terlebih dahulu. Sama seperti dengan perulangan foreach , continue berlanjut ke item berikutnya dalam koleksi atau keluar switch jika tidak ada item lagi. Kita dapat menulis ulang contoh terakhir tersebut dengan pernyataan lanjutan sehingga hanya satu pernyataan yang dijalankan.

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

Alih-alih mencocokkan ketiga item, item pertama cocok dan sakelar berlanjut ke nilai berikutnya. Karena tidak ada nilai yang tersisa untuk diproses, sakelar keluar. Contoh berikutnya adalah menunjukkan bagaimana kartubebas dapat mencocokkan beberapa item.

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

Karena baris dalam file input dapat berisi kata Error dan Warning, kami hanya ingin yang pertama dijalankan dan kemudian melanjutkan pemrosesan file.

Istirahat

Pernyataan break keluar dari sakelar. Ini adalah perilaku yang sama yang continue disajikan untuk nilai tunggal. Perbedaan ditunjukkan saat memproses array. break menghentikan semua pemrosesan dalam sakelar dan continue berpindah ke item berikutnya.

$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

Dalam hal ini, jika kita mencapai garis yang dimulai dengan Error maka kita mendapatkan kesalahan dan tombol berhenti. Inilah yang pernyataan itu break lakukan untuk kita. Jika kita menemukan Error di dalam string dan bukan hanya di awal, kita menulisnya sebagai peringatan. Kami melakukan hal yang sama untuk Warning. Ada kemungkinan bahwa baris dapat memiliki kata Error dan Warning, tetapi kita hanya perlu satu untuk diproses. Inilah yang continue dilakukan pernyataan untuk kita.

Putuskan label

Pernyataan ini switch mendukung break/continue label seperti 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
        }
    }
}

Saya pribadi tidak suka penggunaan break label tetapi saya ingin menunjukkannya karena mereka membingungkan jika Anda belum pernah melihatnya sebelumnya. Saat Anda memiliki beberapa switch pernyataan atau foreach yang ditumpuk, Anda mungkin ingin memecah lebih dari item paling dalam. Anda dapat menempatkan label pada switch yang dapat menjadi target Anda break.

Enum

PowerShell 5.0 memberi kami enum dan kami dapat menggunakannya dalam sakelar.

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

Jika Anda ingin menyimpan semuanya sebagai enum yang ditik dengan kuat, maka Anda dapat menempatkannya dalam tanda kurung.

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

Tanda kurung diperlukan di sini sehingga sakelar tidak memperlakukan nilai [Context]::Location sebagai string harfiah.

ScriptBlock

Kita dapat menggunakan blok skrip untuk melakukan evaluasi untuk kecocokan jika diperlukan.

$age = 37

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

Ini menambah kompleksitas dan dapat membuat Anda switch sulit dibaca. Dalam kebanyakan kasus di mana Anda akan menggunakan sesuatu seperti ini akan lebih baik untuk digunakan if dan elseif pernyataan. Saya akan mempertimbangkan untuk menggunakan ini jika saya sudah memiliki sakelar besar di tempat dan saya membutuhkan dua item untuk mencapai blok evaluasi yang sama.

Satu hal yang saya pikir membantu dengan legibilitas adalah menempatkan blok skrip dalam tanda kurung.

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

Ini masih mengeksekusi dengan cara yang sama dan memberikan istirahat visual yang lebih baik ketika dengan cepat melihatnya.

$matches Regex

Kita perlu mengunjungi kembali regex untuk menyentuh sesuatu yang tidak segera jelas. Penggunaan regex mengisi $matches variabel. Saya menggunakan lebih banyak $matches ketika saya berbicara tentang Banyak cara untuk menggunakan regex. Berikut adalah sampel cepat untuk memperlihatkannya dalam tindakan dengan kecocokan bernama.

$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

Anda dapat mencocokkan $null nilai yang tidak harus default.

$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

Saat menguji string kosong dalam switch pernyataan, penting untuk menggunakan pernyataan perbandingan seperti yang ditunjukkan dalam contoh ini alih-alih nilai ''mentah . Dalam pernyataan switch , nilai '' mentah juga cocok $nulldengan . Contohnya:

$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

Juga, berhati-hatilah dengan pengembalian kosong dari cmdlet. Cmdlet atau alur yang tidak memiliki output diperlakukan sebagai array kosong yang tidak cocok dengan apa pun, termasuk huruf besar/kecil default .

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

Ekspresi konstan

Lee Dailey menunjukkan bahwa kita dapat menggunakan ekspresi konstan $true untuk mengevaluasi [bool] item. Bayangkan jika kita memiliki beberapa pemeriksaan boolean yang perlu terjadi.

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

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

Ini adalah cara bersih untuk mengevaluasi dan mengambil tindakan pada status beberapa bidang boolean. Hal keren tentang ini adalah Anda dapat memiliki satu kecocokan membalikkan status nilai yang belum dievaluasi.

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

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

Pengaturan $isEnabled ke $true dalam contoh ini memastikan bahwa $isVisible juga diatur ke $true. Kemudian ketika $isVisible dievaluasi, blok skripnya dipanggil. Ini sedikit kontra-intuitif tetapi merupakan penggunaan mekanisme yang cerdas.

$switch variabel otomatis

switch Ketika memproses nilai-nilainya, ia membuat enumerator dan memanggilnya $switch. Ini adalah variabel otomatis yang dibuat oleh PowerShell dan Anda dapat memanipulasinya secara langsung.

$a = 1, 2, 3, 4

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

Ini memberi Anda hasil dari:

2
4

Dengan memindahkan enumerator ke depan, item berikutnya tidak diproses oleh tetapi Anda dapat mengakses nilai tersebut switch secara langsung. Aku akan menyebutnya gila.

Pola lainnya

Hashtable

Salah satu posting saya yang paling populer adalah yang saya lakukan pada hashtable. Salah satu kasus penggunaan untuk hashtable adalah menjadi tabel pencarian. Itu adalah pendekatan alternatif untuk pola umum yang sering diatasi oleh switch pernyataan.

$day = 3

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

$lookup[$day]
Wednesday

Jika saya hanya menggunakan switch sebagai pencarian, saya sering menggunakan hashtable sebagai gantinya.

Enum

PowerShell 5.0 memperkenalkan Enum dan ini juga merupakan opsi dalam kasus ini.

$day = 3

enum DayOfTheWeek {
    Sunday
    Monday
    Tuesday
    Wednesday
    Thursday
    Friday
    Saturday
}

[DayOfTheWeek]$day
Wednesday

Kita bisa pergi sepanjang hari melihat berbagai cara untuk menyelesaikan masalah ini. Aku hanya ingin memastikan kau tahu kau punya pilihan.

Kata-kata akhir

Pernyataan switch sederhana di permukaan tetapi menawarkan beberapa fitur canggih yang tidak disadari sebagian besar orang tersedia. Meringkas fitur-fitur tersebut bersama-sama menjadikan ini fitur yang kuat. Kuharap kau mempelajari sesuatu yang belum kau sadari sebelumnya.