switch — 값에 따라 여러 스크립트 중 하나 실행하기

switch — 값에 따라 여러 스크립트 중 하나 실행하기

여러 조건을 나열하고 그중 하나를 골라 실행하고 싶을 때 if를 쓸 수도 있지만, 좀 더 선언적으로 처리하고 싶다면 switch가 좋아요. 어떤 값이 여러 패턴 중 무엇과 일치하는지 판단해, 그에 해당하는 본문을 실행하는 명령이에요.

출처: Tcl 공식 문서 - switch

본문

switch ?options? string pattern body ?pattern body ...?

switch ?options? string {pattern body ?pattern body ...?}

switch 명령은 string 인자를 pattern 인자들과 차례로 대조해요. string과 일치하는 패턴을 찾는 즉시 그 뒤의 body 인자를 Tcl 인터프리터에 재귀적으로 넘겨 평가하고, 그 평가 결과를 반환해요. 마지막 패턴 인자가 default이면 무엇이든 일치해요. 일치하는 패턴이 없고 default도 없으면 switch는 빈 문자열을 반환해요.

switch의 처음 인자들이 -로 시작하면 옵션으로 취급돼요. 단, switch에 인자가 정확히 두 개인 경우는 예외인데, 그때는 첫 번째가 string이고 두 번째가 패턴/본문 리스트여야 해요. 지원되는 옵션은 다음과 같아요.

  • -exact: string을 패턴과 비교할 때 정확히 일치(exact matching)를 사용해요. 기본값이에요.
  • -glob: 패턴과 비교할 때 glob 스타일 매칭(string match 명령과 동일한 방식)을 사용해요.
  • -regexp: 정규 표현식 매칭을 사용해요 (re_syntax 문서 참조).
  • -nocase: 비교를 대소문자 구분 없이 처리해요.
  • -matchvar varName: (-regexp 지정 시에만 사용 가능) 정규 표현식 엔진이 찾은 일치 항목 리스트를 쓸 변수 이름을 지정해요. 리스트의 첫 요소는 입력 문자열(switchstring 인자)에서 일치한 전체 부분 문자열이고, 두 번째 요소는 첫 번째 캡처 괄호가 일치한 부분 문자열이고, 이런 식으로 이어져요. default 분기를 타면 변수에 빈 리스트가 써져요. -indexvar 옵션과 함께 지정할 수 있어요.
  • -indexvar varName: (-regexp 지정 시에만 사용 가능) 일치 부분 문자열을 가리키는 인덱스 리스트를 쓸 변수 이름을 지정해요. 리스트의 첫 요소는 regexp-indices 옵션이 얻는 것과 비슷하게, 전체 일치 부분 문자열의 시작 인덱스와 끝난 뒤 첫 문자 인덱스를 지정하는 두 요소짜리 리스트예요. 마찬가지로 두 번째 요소는 첫 번째 캡처 괄호를 가리키고 이어져요. default 분기를 타면 빈 리스트가 써져요. -matchvar 옵션과 함께 지정할 수 있어요.
  • --: 옵션의 끝을 표시해요. 그 뒤 인자는 -로 시작해도 string으로 취급돼요. 매칭 패턴과 본문이 단일 인자로 묶여 있을 때는 필요 없어요.

패턴과 본문 인자에는 두 가지 문법이 제공돼요. 첫 번째는 각 패턴과 명령마다 별도의 인자를 쓰는 형태예요. 일부 패턴이나 명령에 치환을 원할 때 편리해요. 두 번째 형태는 모든 패턴과 명령을 단일 인자에 함께 넣는 형태예요. 이 인자는 적절한 리스트 구조를 가져야 하는데, 리스트 요소가 패턴과 명령이 돼요. 두 번째 형태는 전체 리스트를 감싸는 중괄호 덕분에 각 줄 끝에 백슬래시를 붙일 필요가 없어서, 여러 줄짜리 switch 명령을 만들기 쉬워요. 두 번째 형태에서는 패턴 인자가 중괄호 안에 있어서 그 패턴에 대해 명령 치환이나 변수 치환이 수행되지 않아요. 그래서 어떤 경우에는 두 번째 형태의 동작이 첫 번째와 달라져요.

본문이 -로 지정되면, 다음 패턴의 본문을 이 패턴의 본문으로도 사용한다는 뜻이에요(다음 패턴도 본문이 -이면 그 다음 본문이 사용되고, 계속 이어져요). 이 기능으로 여러 패턴이 하나의 본문을 공유할 수 있어요.

switch 명령 안에서 주석을 어떻게 두는지 주의하세요. 주석은 패턴들 사이가 아니라, 패턴 중 하나의 실행 본문 안에만 두어야 해요.

예제

switch는 리터럴뿐 아니라 변수와도 대조할 수 있어요(결과는 2).

set foo "abc"
switch abc a - b {expr {1}} $foo {expr {2}} default {expr {3}}

glob 매칭과 폴스루(fall-through) 본문을 쓰는 건, 정규 표현식의 대안(alternation)을 쓰는 것의 대안이에요. 이 예시는 1을 반환해요.

switch -glob aaab {
    a*b     -
    b       {expr {1}}
    a*      {expr {2}}
    default {expr {3}}
}

아무것도 일치하지 않으면 default 절(반드시 마지막에 와야 해요)이 실행돼요. 이 예시의 결과는 3이에요.

switch xyz {
    a -
    b {
        # Correct Comment Placement
        expr {1}
    }
    c {
        expr {2}
    }
    default {
        expr {3}
    }
}

정규 표현식으로 대조할 때, 정확히 무엇이 일치했는지에 대한 정보는 -matchvar 옵션으로 쉽게 얻을 수 있어요.

switch -regexp -matchvar foo -- $bar {
    a(b*)c {
        puts "Found [string length [lindex $foo 1]] 'b's"
    }
    d(e*)f(g*)h {
        puts "Found [string length [lindex $foo 1]] 'e's and\
                [string length [lindex $foo 2]] 'g's"
    }
}

더 알아보기

  • for — 반복
  • if — 조건 분기
  • regexp — 정규 표현식 매칭