다음을 통해 공유


switch 문에 대해 알고 싶었던 모든 것

다른 많은 언어와 마찬가지로 PowerShell에는 스크립트 내에서 실행 흐름을 제어하는 명령이 있습니다. 이러한 명령문 중 하나는 switch 문이며 PowerShell에서는 다른 언어에서 찾을 수 없는 기능을 제공합니다. PowerShell switch작업을 깊이 있게 살펴보는 오늘입니다.

비고

이 문서의 원래 버전@KevinMarquette작성한 블로그에 나타났습니다. PowerShell 팀은 이 콘텐츠를 공유해 주신 Kevin에게 감사드립니다. PowerShellExplained.com자신의 블로그를 확인하세요.

if 선언문

학습한 첫 번째 문 중 하나는 if 문입니다. 문장이 $true인 경우 스크립트 블록을 실행할 수 있게 합니다.

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

elseifelse 문을 사용하여 훨씬 더 복잡한 논리를 가질 수 있습니다. 다음은 요일의 숫자 값이 있고 이름을 문자열로 가져오는 예제입니다.

$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

이것은 일반적인 패턴이며 이를 처리하는 여러 가지 방법이 있습니다. 그 중 하나는 switch을 가지고 있습니다.

Switch 문

switch 문을 사용하면 변수와 가능한 값 목록을 제공할 수 있습니다. 값이 변수와 일치하면 해당 scriptblock이 실행됩니다.

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

이 예제에서는 $day 값이 숫자 값 중 하나와 일치한 다음 올바른 이름이 $result할당됩니다. 이 예제에서는 변수 할당만 수행하지만 해당 스크립트 블록에서 PowerShell을 실행할 수 있습니다.

변수에 할당

마지막 예제를 다른 방법으로 작성할 수 있습니다.

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

PowerShell 파이프라인에 값을 배치하고 $result에 값을 할당합니다. ifforeach 문을 사용하여 이 작업을 수행할 수 있습니다.

기본값

default 키워드를 사용하여 일치하는 항목이 없는 경우 발생할 작업을 식별할 수 있습니다.

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

여기서는 기본 사례에서 Unknown 값을 반환합니다.

현악기들

마지막 예제에서 숫자를 일치시켰지만, 문자열을 일치시킬 수도 있습니다.

$item = 'Role'

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

나는 Component,Role, Location 일치를 따옴표로 묶지 않기로 결정했으며, 이는 그것들이 선택 사항임을 강조하기 위함입니다. switch 대부분의 경우 문자열로 처리합니다.

배열

PowerShell switch 멋진 기능 중 하나는 배열을 처리하는 방법입니다. switch 배열을 지정하면 해당 컬렉션의 각 요소를 처리합니다.

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

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

배열에 반복된 항목이 있는 경우 해당 섹션에 의해 여러 번 일치합니다.

PSItem

$PSItem 또는 $_ 사용하여 처리된 현재 항목을 참조할 수 있습니다. 간단한 일치를 수행할 때 $PSItem 일치하는 값입니다. 이 변수가 사용되는 다음 섹션에서 몇 가지 고급 일치를 수행합니다.

매개 변수

PowerShell switch 고유한 기능은 성능 방식을 변경하는 여러 스위치 매개 변수가 있다는 것입니다.

-대소문자 구분

일치 항목은 기본적으로 대/소문자를 구분하지 않습니다. 대/소문자를 구분해야 하는 경우 -CaseSensitive사용할 수 있습니다. 다른 스위치 매개 변수와 함께 사용할 수 있습니다.

-와일드 카드

-Wildcard 스위치를 사용하여 와일드카드 지원을 사용하도록 설정할 수 있습니다. -like 연산자로 동일한 와일드카드 논리를 사용하여 각 일치를 수행합니다.

$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

여기서는 메시지를 처리한 다음 내용에 따라 다른 스트림에 출력합니다.

-Regex

switch 문은 와일드카드와 마찬가지로 정규식 일치를 지원합니다.

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

내가 쓴 다른 문서에서 regex를 사용하는 더 많은 예가 있습니다 : regex사용하는 여러 가지 방법입니다.

-파일

switch 문의 잘 알려지지 않은 기능은 그것이 -File 매개 변수를 사용하여 파일을 처리할 수 있다는 것입니다. 변수 식을 제공하는 대신 파일 경로와 함께 -File 사용합니다.

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

배열을 처리하는 것처럼 작동합니다. 이 예제에서는 와일드카드 일치와 결합하고 $PSItem사용합니다. 이렇게 하면 로그 파일이 처리되고 regex 일치 항목에 따라 경고 및 오류 메시지로 변환됩니다.

고급 세부 정보

이제 이러한 문서화된 모든 기능을 인식했으므로 고급 처리의 컨텍스트에서 사용할 수 있습니다.

표현식

switch 변수 대신 식에 있을 수 있습니다.

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

식이 평가되어 나온 값은 일치 항목에 사용되는 값입니다.

여러 일치 항목

아마도 이미 알아차렸겠지만, switch는 여러 조건과 일치할 수 있습니다. -Wildcard 또는 -Regex 일치 항목을 사용하는 경우 특히 그렇습니다. 동일한 조건을 여러 번 추가할 수 있으며 모두 트리거됩니다.

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

이 세 가지 주장은 모두 무효화되었습니다. 이는 모든 조건이 차례대로 검토되었음을 보여 줍니다. 각 항목이 각 조건을 확인하는 배열을 처리하는 경우 이는 참입니다.

계속

일반적으로 break 문을 소개하는 곳이지만 먼저 continue 사용하는 방법을 배우는 것이 좋습니다. foreach 루프와 마찬가지로 continue 컬렉션의 다음 항목으로 계속 이동하거나 항목이 더 이상 없으면 switch 종료합니다. 마지막 예제를 continue 문으로 다시 작성하여 하나의 문만 실행할 수 있습니다.

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

세 항목을 모두 일치시키는 대신 첫 번째 항목이 일치하고 스위치가 다음 값으로 계속됩니다. 처리할 값이 없으므로 스위치가 종료됩니다. 다음 예제에서는 와일드카드가 여러 항목과 일치할 수 있는 방법을 보여 줍니다.

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

입력 파일의 줄에 Error 단어와 Warning모두 포함될 수 있으므로 첫 번째 줄만 실행한 다음 파일 처리를 계속하려고 합니다.

휴식

break 문장이 switch 문에서 빠져나옵니다. 이는 continue 단일 값에 대해 제시하는 것과 동일한 동작입니다. 배열을 처리할 때 차이가 표시됩니다. break 스위치의 모든 처리를 중지하고 continue 다음 항목으로 이동합니다.

$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

이 경우 Error 시작하는 줄에 도달하면 오류가 발생하며 스위치가 중지됩니다. 이것이 바로 break 진술이 우리를 위해 하는 일입니다. 문자열에서 Error이 처음에만 있는 것이 아니라 내부에 발견되면 경고로 기록합니다. 우리는 Warning대해 같은 일을합니다. 줄에는 ErrorWarning두 단어가 모두 있을 수 있지만, 처리에는 둘 중 하나만 필요합니다. 이것이 continue 진술이 우리를 위해 하는 일입니다.

레이블 중단

switch 문은 break/continue 레이블을 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
        }
    }
}

개인적으로는 브레이크 레이블의 사용을 좋아하지 않지만, 그것들을 이전에 본 적이 없다면 혼란스러울 수 있어 지적하고 싶었습니다. 중첩된 switch 또는 foreach 문이 여러 개 있는 경우 가장 안쪽 항목보다 더 많은 항목을 분리할 수 있습니다. switch에 레이블을 붙여 break의 대상으로 만들 수 있습니다.

열거형

PowerShell 5.0은 열거형을 도입했으며, 이를 스위치에서 사용할 수 있습니다.

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

모든 항목을 강력한 형식의 열거형으로 유지하려는 경우 괄호 안에 배치할 수 있습니다.

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

여기서는 스위치가 [Context]::Location 값을 리터럴 문자열로 처리하지 않도록 괄호가 필요합니다.

ScriptBlock

필요한 경우 scriptblock을 사용하여 일치 항목에 대한 평가를 수행할 수 있습니다.

$age = 37

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

이렇게 하면 복잡성이 추가되고 switch 읽기 어려울 수 있습니다. 이와 같은 항목을 사용하는 대부분의 경우 ifelseif 문을 사용하는 것이 좋습니다. 이미 대형 스위치가 설치되어 있고 동일한 평가 블록에 도달하기 위해 두 항목이 필요한 경우 이를 고려할 것입니다.

가독성에 도움이 된다고 생각하는 한 가지는 scriptblock을 괄호 안에 배치하는 것입니다.

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

여전히 동일한 방식으로 실행되며, 빠르게 살펴볼 때 시각적으로 더 잘 구분됩니다.

Regex $Matches

우리는 즉시 명확하지 않은 무언가를 다루기 위해 정규 표현식을 다시 살펴봐야 합니다. regex를 사용하면 $Matches 변수가 채워집니다. 내가 에 대해 이야기할 때 $Matches의 사용법을 더 설명하며 regex를에서 사용하는 여러 가지 방법에 대해 이야기합니다. 명칭을 정한 매칭의 작동을 보여주는 간단한 샘플입니다.

$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

기본값이 될 필요가 없는 $null 값을 일치시킬 수 있습니다.

$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

switch 문에서 빈 문자열을 테스트할 때는 원시 값 ''대신 이 예제와 같이 비교 문을 사용해야 합니다. switch 문에서 원시 값 ''$null와 일치합니다. 다음은 그 예입니다.

$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

또한 cmdlet의 빈 반환에 주의해야 합니다. 출력이 없는 cmdlet 또는 파이프라인은 default 사례를 포함하여 아무것도 일치하지 않는 빈 배열로 처리됩니다.

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

상수 식

Lee Dailey는 상수 $true 식을 사용하여 [bool] 항목을 평가할 수 있다고 지적했습니다. 여러 개의 부울 검사가 필요하다고 가정해 보십시오.

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

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

이는 여러 부울 필드의 상태를 평가하고 조치를 취하는 깨끗한 방법입니다. 이에 대한 멋진 점은 하나의 일치 항목이 아직 평가되지 않은 값의 상태를 뒤집을 수 있다는 것입니다.

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

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

이 예제에서 $isEnabled$true으로 설정하면 $isVisible$true으로 설정되도록 합니다. 그런 다음 $isVisible 평가되면 해당 scriptblock이 호출됩니다. 이것은 약간 직관적이지 않지만 역학을 영리하게 사용합니다.

자동 변수 $switch

switch 값을 처리할 때 열거자를 만들고 $switch호출합니다. PowerShell에서 만든 자동 변수이며 직접 조작할 수 있습니다.

$a = 1, 2, 3, 4

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

그러면 다음과 같은 결과가 표시됩니다.

2
4

열거자를 앞으로 이동하면 다음 항목이 switch 처리되지 않지만 해당 값에 직접 액세스할 수 있습니다. 나는 그것을 광기라고 부를 것이다.

기타 패턴

해시 테이블

내 가장 인기 있는 게시물 중 하나는 내가 해시 테이블에 대해 다룬 것입니다. hashtable 사용 사례 중 하나는 조회 테이블이 되는 것입니다. 이는 switch 문이 자주 다루는 일반적인 패턴에 대한 대체 방법입니다.

$day = 3

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

$lookup[$day]
Wednesday

switch를 단순 조회로만 사용할 경우, 대신 hashtable을 사용하는 경우가 많습니다.

열거형

PowerShell 5.0은 enum 도입했으며 이 경우에도 옵션입니다.

$day = 3

enum DayOfTheWeek {
    Sunday
    Monday
    Tuesday
    Wednesday
    Thursday
    Friday
    Saturday
}

[DayOfTheWeek]$day
Wednesday

우리는 하루 종일이 문제를 해결하는 다른 방법을 찾고 갈 수 있습니다. 난 그냥 당신이 옵션이 있다는 것을 알고 있는지 확인하고 싶었다.

마지막 단어

스위치 문은 표면에서 간단하지만 대부분의 사람들이 인식하지 못하는 몇 가지 고급 기능을 제공합니다. 이러한 기능을 함께 묶으면 강력한 기능이 됩니다. 난 당신이 전에 실현하지 않은 무언가를 배웠으면 좋겠다.