본문으로 바로가기

Tcl의 문법

category 카테고리 없음 2024. 4. 12. 13:20

Tcl의 문법은 상당히 단순하고, 커맨드의 인자를 스페이스(공백)로 단락을 짓고 나열하는 정도입니다.

command arg1 arg2 arg3 ...


한 행에 여러 개의 커맨드를 나열할 때는, 세미콜론( ; )으로 구분을 짓습니다.

command arg1 arg2 arg3 ... ; command arg1 arg2 arg3 ...


한 행이 길어질 때는, 행 끝에 백슬래쉬(\)를 두는 것으로 계속 이어 쓸 수 있습니다.

command arg1 \
    arg2 arg3 ...


다음의 간단한 예제를 보겠습니다.

Hello World

Hello World를 표시하는 스크립트입니다. puts 커맨드는 문자를 표시하는 커맨드입니다. 두 개의 예제는 같은 결과를 나타냅니다.

puts stdout {Hello World}
=>Hello World
puts stderr {Hello World}
=>Hello World
puts {Hello World}
=>Hello World
puts stdout "Hello World"
=>Hello World
puts stderr "Hello World"
=>Hello World
puts "Hello World"
=>Hello World

변수

Tcl의 변수에는 타입이 없습니다. 타입을 의식하지 않고 문자열이나 정수를 변수에 대입할 수 있습니다. set 커맨드는, 변수에 값을 대입합니다. set 커맨드로 값을 생략하고, 변수명의 처음에 $을 붙여주면 값을 참조할 수 있습니다. unset 커맨드는, 변수를 메모리에서 삭제합니다.

set var 123
=>123
set var
=>123
set var abc
=>abc
puts stdout $var
=>abc
unset var

산술연산

expr 커맨드는, 정수나 부동소수점의 연산이나 비교를 행합니다. 삼각 함수나 난수등도 사용할 수 있습니다.

expr 1 / 0
=>divide by zero
expr 10 + 0x10 + 010
=>34
expr 2.0 * asin(1.0)
=>3.14159265359
set i 1
=>1
incr i
=>2

커맨드의 치환

대괄호[]는, 대괄호내의 커맨드를 커맨드의 출력결과로 치환해 줍니다.

set pi [expr 2.0 * asin(1.0)]
=>3.14159265359
set pi
=>3.14159265359

더블 쿼테이션(Double Quotation Mark)과 중괄호

더블 쿼테이션과 중괄호는, 여러 개의 문자열을 하나의 덩어리로 묶어줍니다. 단 더블 쿼테이션 내에서 변수와 커맨드는 치환이 되지만, 중괄호 내에서는 치환이 되지 않습니다. 백슬래쉬(\) 사용한다면 ‘[’과 ‘$’의 치환기능을 무효화시킬 수 있습니다.

set var 123
=>123
puts "result = $var"
=>result = 123
puts {result = $var}
=>result = $var
puts "result = \$var"
=>result = $var
set var 123
=>123
puts "result = [pwd]"
=>result = C:/
puts {result = [pwd]}
=>result = [pwd]
puts "result = \[var]"
=>result = [var]

포맷(format)

scan과 format 커맨드는 ANSI C언어의 scan과 printf함수와 서식이 같습니다. %의 서식에 의하여 문자열을 포맷합니다.

scan "123.456" "%d.%d" a b
=>2
set a
=>123
set b
=456
format "%d.%d" $a $b
=>123.456

프로시져(Procedure)

proc 커맨드는, 0개 이상의 인자를 받는 프로시져를 정의할 수 있습니다. 프로시져 안에서 정의된 변수는, 프로시져 안에서만 참조할 수 있습니다. 프로시져 밖에서 변수를 참조하고 싶다면, 변수가 선언된 프로시져와 참조할 프로시져 안에서 global로 변수를 선언하면 됩니다. 프로시져는 디폴트로 인자나, 가변인자를 받는 것도 가능합니다.

# 보통의 인자
set foo 3
=>3
proc add {a b} {
   global foo
   return [expr $a + $b + $foo]
}
add 1 2
=>6

# 참조형 인자와 디폴트 인자
proc plus {a {b 1}} {
   upvar $a r
   set r [expr $r + $b]
   return $r
}
set foo 1
=>1
plus foo
=>2
plus foo 2
=>4

# 가변 인자
proc sum {args} {
   set s 0
   foreach i $args {
      set s [expr $s + $i]
   }
   return $s
}
sum 1 2
=>3
sum 1 2 3
=> 6

주석(comment)

#로 시작하는 행은 주석의 행을 의미합니다. 스크립트 기술 도중 주석을 기술 시에는 ;#가 돼야 합니다.

# 주석 1
# 주석 2 \
   주석 2의 계속
puts {Hello World} ; #주석 3
=>Hello World

제어문

if, for, foreach, while, switch 커맨드는 제어문으로 사용하는 커맨드입니다. if, for, while의 조건식은 expr 커맨드와 같이 사용할 수 있습니다.

if, elseif, else문

set var 일
=>일
if {$var == "일"} {
   puts stdout 1
}
=>1
 
set var 이
=>이
if {$var == "일"} {
   puts stdout 1
} else {
   puts stdout 2
}
=>2
 
set var 삼
=>삼
if {$var == "일"} {
   puts stdout 1
} elseif {$var == "이"} {
   puts stdout 2
} else {
   puts stdout 3
}
=>3


for, foreach, while안에서는 continue, break 커맨드를 사용할 수 있습니다.

for 문

for {set i 1} {$i <= 3} {incr i} {
   puts stdout $i
}
=>1
=>2
=>3
 
for {set i 1} {$i <= 5} {incr i} {
   if {$i < 3} {
      continue
   }
   puts stdout $i
}
=>3
=>4
=>5
 
for {set i 1} {$i <= 5} {incr i} {
   if {$i > 3} {
      break
   }
   puts stdout $i
}
=>1
=>2
=>3

while 문

set i 3
=>3
while {$i != 0} {
   puts stdout $i
   incr i -1
}
=>3
=>2
=>1

foreach 문

foreach i {A B C} {
   puts stdout $i
}
=>A
=>B
=>C
 
foreach {i j} {A B C D E F} {
   puts stdout "$i $j"
}
=> A B
=> C D
=> E F

switch 문

switch 사과 {
   사과    {puts 100원}
   귤나무    {puts 80원}
   바나나(banana)  {puts 30원}
   default   {puts 모름}
}
=>100원
 
switch 사과 {
   사과
      {puts 100원}
   귤나무
      {puts 80원}
   바나나
      {puts 30원}
   default
      {puts 모름}
}
=>100원

after 문

after커맨드는, 커맨드의 실행시간을 지연시키는 일을 합니다. after로 지정한 커맨드는 global scope에서 실행된다는 것을 주의해야 합니다.

after 1000 ;# 1초 기다리다가..
after 1000 "set a 1" ;# 1초후에 커맨드를 실행
=>after#0

catch 문

catch 커맨드는, 에러를 캐치(catch)하는 데 사용됩니다. 에러가 발생하면 1을 리턴 시켜주고, 아니면 0을 리턴 시켜줍니다.

catch {expr 1+2} var
=>0
catch {expr 1*_} var
=>1
catch {expr 1/0} var
=>1
catch {error bug} var
=>1

에러처리

에러처리의 기술이 없다면, 에러발생 시에 아래와 같은 창이 나타납니다.

 

에러처리는 잊지 말고 꼭 처리해주어야 합니다.

proc foo1 {} {
   return -code error -errorcode 1 -errorinfo info message
}
 
proc foo2 {} {
   error message info 1
}
 
if [catch foo1] {
   puts "errorCode = $errorCode"
   puts "errorInfo = $errorInfo"
}
 
if [catch foo2] {
   puts "errorCode = $errorCode"
   puts "errorInfo = $errorInfo"
}

배열

배열의 첨자에 문자열을 사용할 수 있습니다. parray커맨드는, 배열의 요소를 표시합니다.

set ary(사과) 100원
=>100원
set ary(귤나무) 80원
=>80원
set ary(바나나) 30원
=>30원
parray ary
=>ary(사과) = 100원
=>ary(귤나무) = 80원
=>ary(바나나) = 30원
puts $ary(사과)
=>100원
 
array set ary {
   사과 100원
   귤나무 80원
   바나나 30원
}
parray ary
=>ary(사과) = 100원
=>ary(귤나무) = 80원
=>ary(바나나) = 30원
puts $ary(사과)
=>100원

리스트

lisp와 비슷한 리스트가 준비되어 있습니다.

set list { 사과 귤나무 바나나 }
=>사과 귤나무 바나나
lappend list 멜론
=>사과 귤나무 바나나 멜론
lindex $list 2
=>바나나
lsort $list
=>귤나무 사과 바나나 멜론

문자열

문자나 문자열을 위한 커맨드가 준비되어 있습니다.

if ![string compare -nocase "abc" "ABC"] {
   puts 같다
}
=>같다
string toupper "abc"
=>ABC
string length "xyz"
=>3
string length "귤나무"
=>3
split usr/local/bin /
=>usr local bin
join {usr local bin} /
=>usr/local/bin /
set str abc
=>abc
append str xyz
=>abcxyz

바이너리

물론 바이너리 문자도 지원합니다.

# ASCII to Binary
set bin [binary format i 0x12345678]
# Binary to ASCII
binary scan $bin H2H2H2H2 var1 var2 var3 var4
puts 0x$var4$var3$var2$var1
=>0x12345678

스크립트의 인자

스크립트 파일의 인자는, argc와 argv 변수로 알아낼 수 있습니다.

set 스크립트이름 $argv0
set 인자의수 $argc
set 제1인자 [lindex $argv 0]
set 제2인자 [lindex $argv 1]
set 제3인자 [lindex $argv 2]