switch — 값에 따라 여러 스크립트 중 하나 실행하기
switch — 값에 따라 여러 스크립트 중 하나 실행하기
여러 조건을 나열하고 그중 하나를 골라 실행하고 싶을 때 if를 쓸 수도 있지만, 좀 더 선언적으로 처리하고 싶다면 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지정 시에만 사용 가능) 정규 표현식 엔진이 찾은 일치 항목 리스트를 쓸 변수 이름을 지정해요. 리스트의 첫 요소는 입력 문자열(switch의string인자)에서 일치한 전체 부분 문자열이고, 두 번째 요소는 첫 번째 캡처 괄호가 일치한 부분 문자열이고, 이런 식으로 이어져요.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"
}
}