Tclの文法

Tclの文法は、すごく単純でコマンドと引数をスペースで区切って並べるだけです。

command arg1 arg2 arg3 ...

一行に複数のコマンドを並べる時は、セミコロンで区切ります。

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

一行が長くなる時は、行末にバックスラッシュを置くことで継続できます。

command arg1 \
    arg2 arg3 ...

それでは、簡単なサンプルを見てください。

日本語を使う場合は、Tcl8.1以上をお使いください。
=>印行は、コマンドの出力行を意味します。

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

ダブルクォートと中括弧

ダブルクォートと中括弧は、複数の文字列を一塊にまとめます。
ただし、ダブルクォート内で変数とコマンドは置換されますが、
中括弧内では置換されません。
バックスラッシュを使うと'['と'$'の置換効果を無効にできます。

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 = [pwd]

フォーマット

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

プロシジャ

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 

コメント

#で始まる行は、コメント行を意味します。
ステートメントの途中からコメントを記述するには、
;#となる点に注意してください。

# コメント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円}
バナナ  {puts 30円}
default	{puts 不明}
}
=>100円
switch りんご {
りんご
	{puts 100円}
みかん
	{puts 80円}
バナナ
	{puts 30円}
default
	{puts 不明}
}
=>100円

afterコマンドは、コマンドの実行時間を遅延させることができます。
afterで指定したコマンドはglobalスコープで実行されることに注意してください。

after文
after 1000 ;# 1秒待つ
after 1000 "set a 1" ;# 1秒後にコマンドを実行する
=>after#0

catchコマンドは、エラーをキャッチするのに使います。
エラーが発生した時は、1を返します。それ以外は0を返します。
errorコマンドは、エラーを故意に発生するのに使います。

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

エラー処理

エラー処理の記述がないと、エラー発生時にこのようなダイアログが出ます。
エラー処理は忘れずに記述しましょう。

# エラーを返すコマンド(その1)
proc foo1 {} {
   return -code error -errorcode 1 -errorinfo info message
}

# エラーを返すコマンド(その2)
proc foo2 {} {
   error message info 1
}

# エラーを想定した処理(その1)
if [catch foo1] {
    puts "errorCode = $errorCode"
    puts "errorInfo = $errorInfo"
}

# エラーを想定した処理(その2)
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]