about_Break — break 문으로 제어 블록을 빠져나오기

about_Break — break 문으로 제어 블록을 빠져나오기

PowerShell에서 반복문이나 switch 같은 제어 블록을 중간에 빠져나오고 싶을 때 쓰는 게 바로 break 문이에요. 이 문서에서는 break를 반복문·switch·trap에서 어떻게 활용하는지, 라벨과 함께 쓰는 고급 기법부터 잘못 쓰면 위험한 상황까지 하나씩 살펴볼게요.

출처: about_Break - PowerShell | Microsoft Learn

본문

간단한 설명 (Short description)

break 문이 무엇인지, 언제 쓰는지 설명해요. break는 현재 제어 블록을 빠져나가는 방법을 제공합니다.

자세한 설명 (Long description)

break 문은 현재 제어 블록을 빠져나가는 방법을 줘요. 빠져나가고 나면 실행은 제어 블록 다음에 오는 문장에서 이어집니다. 이 문은 라벨(label) 을 지원하는데, 라벨은 스크립트 안의 어떤 문장에 붙여주는 이름이에요.

반복문에서 break 사용하기

break 문이 foreach, for, do, while 같은 반복문 안에 나타나면, PowerShell은 즉시 그 반복문을 빠져나가요.

break 문에는 라벨을 붙일 수 있는데, 이 라벨로 중첩된 반복문을 빠져나갈 수 있어요. 라벨은 스크립트 안의 foreach, for, while 같은 반복 키워드 어느 것이든 지정할 수 있습니다.

아래 예시는 break 문을 써서 for 문을 빠져나가는 방법을 보여줘요.

for($i=1; $i -le 10; $i++) {
   Write-Host $i
   break
}

이 예시에서 break 문은 $i 변수가 1일 때 for 반복문을 빠져나가요. $i가 10보다 커질 때까지 for 문의 조건이 True로 평가되지만, PowerShell은 반복문이 처음 실행될 때 이미 break 문에 닿게 됩니다.

반복문 안에서 내부 조건을 만족해야 할 때 break를 쓰는 게 더 흔해요. 다음 foreach 문 예시를 살펴볼게요.

$i=0
$varB = 10,20,30,40
foreach ($val in $varB) {
  if ($val -eq 30) {
    break
  }
  $i++
}
Write-Host "30 was found in array index $i"

이 예시에서 foreach 문은 $varB 배열을 반복해요. if 문은 반복이 처음 두 번 실행되는 동안 False로 평가되고, $i 변수는 1씩 증가합니다. 세 번째 반복에서 $i는 2가 되고 $val 변수는 30이 돼요. 이 시점에 break 문이 실행되고 foreach 반복문이 빠져나갑니다.

반복문에서 라벨이 붙은 break 사용하기

break 문에는 라벨을 붙일 수 있어요. break 키워드를 라벨과 함께 쓰면, PowerShell은 현재 반복문 대신 라벨이 붙은 반복문을 빠져나가요. 라벨은 콜론 뒤에 붙이는 이름 형태로, 여러분이 직접 정합니다. 라벨은 문장의 첫 번째 토큰이어야 하고, 그 뒤에는 while 같은 반복 키워드가 따라와야 합니다.

break는 실행 흐름을 라벨이 붙은 반복문 밖으로 옮겨요. 중첩된 반복문에서는 이 동작이 라벨 없이 쓰는 break 키워드와 다른 결과를 냅니다. 아래 예시는 while 문 안에 for 문이 들어 있는 경우예요.

:myLabel while (<condition 1>) {
  foreach ($item in $items) {
    if (<condition 2>) {
      break myLabel
    }
    $item = $x   # A statement inside the For-loop
  }
}
$a = $c  # A statement after the labeled While-loop

condition 2가 True로 평가되면, 스크립트의 실행은 라벨이 붙은 반복문 다음의 문장으로 건너뜁니다. 이 예시에서는 $a = $c 문부터 다시 실행이 시작돼요.

라벨이 붙은 반복문은 아래 예시처럼 여러 겹으로 중첩할 수도 있어요.

:red while (<condition1>) {
  :yellow while (<condition2>) {
    while (<condition3>) {
      if ($a) {break}
      if ($b) {break red}
      if ($c) {break yellow}
    }
    Write-Host "After innermost loop"
  }
  Write-Host "After yellow loop"
}
Write-Host "After red loop"

$b 변수가 True로 평가되면, 스크립트 실행은 red라는 라벨이 붙은 반복문 다음에서 다시 시작돼요. $c 변수가 True로 평가되면, 실행 제어는 yellow라는 라벨이 붙은 반복문 다음에서 이어집니다.

$a 변수가 True로 평가되면, 실행은 가장 안쪽 반복문 다음에서 이어져요. 이 경우에는 라벨이 필요 없습니다.

PowerShell은 라벨이 실행을 이어갈 수 있는 범위를 제한하지 않아요. 라벨은 심지어 함수와 스크립트 호출 경계를 넘어서 제어권을 넘겨줄 수도 있습니다.

switch 문에서 break 사용하기

switch 구조에서 break는 PowerShell이 switch 코드 블록을 빠져나가게 해요.

break 키워드는 switch 구조를 떠날 때 쓰입니다. 예를 들어, 다음 switch 문은 가장 구체적인 조건을 검사하기 위해 break 문을 사용해요.

$var = "word2"
switch -Regex ($var) {
    "word2" {
      Write-Host "Exact" $_
      break
    }

    "word.*" {
      Write-Host "Match on the prefix" $_
      break
    }

    "w.*" {
      Write-Host "Match on at least the first letter" $_
      break
    }

    default {
      Write-Host "No match" $_
      break
    }
}

이 예시에서 $var 변수는 문자열 값 word2로 만들어지고 초기화돼요. switch 문은 Regex 클래스를 사용해서 먼저 word2라는 용어로 변수 값을 매칭합니다. switch 문 안의 첫 번째 테스트와 변수 값이 일치하므로, switch 문의 첫 번째 코드 블록이 실행됩니다.

PowerShell이 첫 번째 break 문에 닿으면 switch 문이 빠져나가요. 예시에서 네 개의 break 문을 모두 지우면 네 조건이 전부 충족된다는 점에 주목할게요. 이 예시는 가장 구체적인 조건이 충족될 때 결과를 보여주려고 break 문을 사용한 거예요.

trap 문에서 break 사용하기

trap 문의 본문에서 마지막으로 실행되는 문장이 break이면, 오류 개체는 숨겨지고 예외는 다시 throw(thrown) 됩니다.

아래 예시는 trap 문으로 잡히는 DivideByZeroException 예외를 만들어요.

function test {
  trap [DivideByZeroException] {
    Write-Host 'divide by zero trapped'
    break
  }

  $i = 3
  'Before loop'
  while ($true) {
     "1 / $i = " + (1 / $i--)
  }
  'After loop'
}
test

실행이 예외에서 멈추는 걸 볼 수 있어요. After loop는 절대 실행되지 않습니다. trap이 실행된 뒤 예외는 다시 throw 됩니다.

Before loop
1 / 3 = 0.333333333333333
1 / 2 = 0.5
1 / 1 = 1
divide by zero trapped
ParentContainsErrorRecordException:
Line |
  10 |       "1 / $i = " + (1 / $i--)
     |       ~~~~~~~~~~~~~~~~~~~~~~~~
     | Attempted to divide by zero.

반복문·switch·trap 바깥에서는 break를 쓰지 마세요

break를 직접 지원하는 구조(반복문, switch, trap) 바깥에서 사용하면, PowerShell은 그것을 감싸는 구조를 찾기 위해 호출 스택을 살펴봐요. 감싸는 구조를 찾지 못하면 현재 runspace가 조용히 종료됩니다.

즉, break를 직접 지원하는 구조 밖에서 실수로 쓴 함수나 스크립트는 의도치 않게 자신의 호출자를 종료시킬 수 있어요.

ForEach-Object 스크립트 블록 같은 파이프라인 중간에서 break를 쓰면 파이프라인만 나가는 게 아니라, 잠재적으로 runspace 전체를 종료시킬 수도 있습니다.

더 알아보기