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에 할당합니다. 및 foreach 문을 사용하여 이 작업을 if 수행할 수 있습니다.

기본값

키워드(keyword) 사용하여 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하지 않기로 결정하고,RoleLocation 그들이 선택 사항임을 강조하기 위해 여기에 따옴표로 일치합니다. 대부분의 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

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

-Wildcard

스위치를 사용하여 wild카드 지원을 -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 문은 야생처럼 regex 일치를 지원합니다카드.

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

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

-File

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

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

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

고급 세부 정보

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

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

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

식의 평가 대상은 일치에 사용한 값이 됩니다.

여러 일치 항목

이미 이를 선택했을 수 있지만 switch 여러 조건과 일치할 수 있습니다. 사용하거나 -regex 일치할 때 -wildcard 특히 그렇습니다. 동일한 조건을 여러 번 추가할 수 있으며 이 경우 모든 조건이 트리거됩니다.

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 방법을 배우는 것이 좋습니다. 루프 continueforeach 마찬가지로 컬렉션의 다음 항목으로 계속 이동하거나 항목이 더 이상 없으면 종료합니다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
    }
}

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

휴식 시간

break 문이 스위치를 종료합니다. 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로 시작하는 줄에 도달하면 오류가 발생하고 switch가 중단됩니다. 이것이 바로 그 break 진술이 우리를 위해 하는 일입니다. 문자열 내에 Error가 있고 시작 부분이 아니라면 이를 경고라고 작성합니다. 우리는 에 대해 같은 일을합니다 Warning. 한 줄에 ErrorWarning 단어가 모두 포함될 수 있지만 하나만 처리하면 됩니다. continue 문은 바로 이 작업을 수행합니다.

레이블 중단

문은 switch 다음과 같은 foreach레이블을 지원 break/continue 합니다.

: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를 다시 방문해야합니다. regex를 사용하면 변수가 $matches 채워집니다. 나는 regex를 사용하는 $matches 여러 가지 방법에 대해 이야기 할 때 더 많은 사용에 간다. 다음은 명명된 일치 항목의 작동을 보여 줄 빠른 샘플입니다.

$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

이 문제를 해결하는 방법을 모두 살펴보려면 종일 해도 모자랄 것입니다. 여러분에게 이러한 선택지가 있음을 알려드리고 싶을 뿐입니다.

마지막 단어

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