expectコマンドで扱うTcl (Tool Common Langueage)について
この記事では、最低限知っておきたい基本の文法を紹介していきます。
Tclとは
Tcl (Tool Common Language)
読み方は、ティクルです。
expectコマンドくらいでしか自分は目にした事はないですが。。
当時、アプリケーション毎に異なる言語を実装していた時代に、
標準的に使えるもの用意したかったという目的があった。
今なら、もっと違う言語を採用するほうが有益な気もしますが、
Tcl自体はシンプルな文法なのでライブラリ化して、
容易にアプリケーションに組み込めるようにしていたみたいです。
Tclスクリプトの実行
expectコマンドは、Tclのスーパーセットなので、これから記載するコードもexpectコマンドを使えば実行ができます。
expect test.tcl
ただ、tclsh というTcl用のインタプリタがあるので、今回はそちらを使って動作確認しています。
tclsh test.tcl
スクリプトファイルには、#!/usr/bin/tclsh
とShebangをつけて、
実行権限を付与しておくのが良いでしょう。
# tclファイルを用意
cat << EOF > test1.tcl
#!/usr/bin/tclsh
puts "hello"
EOF
# 実行権限付与
chmod +x test1.tcl
# 実行してみる
./test1.tcl
#==> hello
変数と展開
変数の宣言と設定には、setを使います。
# a変数に"hoge"を設定
set a "hoge"
変数を展開して使うときは、$
を利用します。
$
は変数置換と呼ばれるものになります。
# 使う時は$aとする。
puts $a
#==> hoge
コマンドライン引数
コマンドライン引数の内容は、グローバル変数に自動で格納されます。
$argv0
スクリプトファイル名$argc
コマンドライン引数の個数$argv
コマンドライン引数の配列
コマンドライン引数を指定して実行した例
./sample.tcl hoge piyo
puts "ファイル名(argv0): $argv0"
#==> ファイル名(argv0): ./sample.tcl
puts "引数個数(argc): $argc"
#==> 引数個数(argc): 2
puts "引数リスト(argv): $argv"
#==> 引数リスト(argv): hoge piyo
argv変数は、リストになっています。
リストの要素にアクセスする際は、lindexを使うのを覚えておきましょう。
puts [lindex $argv 0]
#==> hoge
puts [lindex $argv 1]
#==> piyo
if文
if文は他の言語に近い感じもしますが、
評価式と処理内容は{}
で囲っておくのが安全です。
if {$a == 0} {
puts "a is zero"
}
elseif と else も使う事ができます。
if {$a == 0} {
puts "a is zero"
} elseif {$a == 1} {
puts "a is one"
} else {
puts "a is other"
}
Tclは文法もリスト構造になっている
Tclは文法自体が、リスト構造になっています。
空白、タブ、改行で区切られるのが基本ですが、{}を使う事で途中に区切り文字が混じっていても一つの要素として扱えます。
通常のコマンドも下記のようなリストと解釈されています。
コマンド 引数1 引数2
if文でさえも実態はリストとして解釈されて処理される。
if 評価式 処理内容
評価式と、処理内容は{}
で囲っている為に要素化される。
末尾を{
にすることで、改行しても要素化が適用されている。
# 正しいif文
if {$a == 0} {
puts "a is zero"
}
# 正しいif文
if {$a == 0} {puts "a is zero"}
下記の例は、{
に入る前に改行してしまっているので、別の一文として扱われます。
if文は処理内容がないと判断される為、エラーとなる。
# 構文エラー
if {$a == 0}
{
puts "a is zero"
}
for文
0-9までのが出力されます。
for {set i 0} {$i < 10} {incr i} {
puts "i: $i"
}
incrは、指定の変数をインクリメントする為のコマンドです。
step数を指定してループさせることも可能です。
0,3,6,9までが出力されます。
for {set i 0} {$i < 10} {incr i 3} {
puts "i: $i"
}
while文
評価式がtrueになる場合にループし続けます。
set i 0
while {$i < 10} {
puts "i: $i"
incr i
}
while true
とすることで無限ループにできます。
breakで抜ける処理を入れておくのを忘れずに。
# 無限ループ
set i 0
while true {
puts "i: $i"
incr i
# breakで抜けれる
if {$i>=10} break
}
関数 (プロシージャ)
Tclでも関数が定義できます。
proc (プロシージャ)というキーワードを使って定義します。
定義した関数は実際にコールする前に、事前にprocで定義している必要があります。
引数なし
引数なしの場合は、関数名の後ろに{}
を配置します。
proc foo {} {
puts "hello"
}
# 関数を実行する
foo
#==> hello
引数あり
引数ありの場合は、関数名の後ろの{}
内にとる引数変数を宣言します。
# 引数あり
proc bar {a b} {
puts "$a and $b"
}
# 関数を実行する
bar hoge piyo
#==> hoge and piyo
返り値を使う (コマンド置換)
return で返された返り値を使う場合、[]
で囲ってコールします。
[]
はコマンド置換というものになります。
proc greet {} {
return "hello"
}
# 返り値を使う
puts [greet]
[]
内のコマンド実行結果に置換して、putsコマンドに渡している。
グローバル変数へのアクセス
プロシージャ内で、グローバル変数にアクセスしたい場合は、global宣言して参照します。
proc foo {} {
# プロシージャ内でグローバル変数にアクセスする場合は、宣言必要。
global argv0
puts "スクリプトファイル名: $argv0"
}
インクリメント/デクリメント
incrコマンドを使います。
# xに1インクリメント
incr x
# xに2インクリメント
incr x 2
デクリメント用のものはないので、incrにマイナス値を渡します。
# xに1デクリメント
incr x -1
# xに2デクリメント
incr x -2
計算式 expr
exprコマンドを使います。
# 加算
puts [expr 10 + 3]
#==> 13
# 引算
puts [expr 10 - 3]
#==> 7
# 掛算
puts [expr 10 * 3]
#==> 30
# 割算
# 整数値同士の計算だと、小数点以下は切り捨てられる。
puts [expr 10 / 3]
#==> 3
# 小数点を使うと、少数値で計算される。
puts [expr 10.0 / 3]
#==> 3.3333333333333335
# 余り
puts [expr 10 % 3]
#==> 1
まとめ
Tclの文法はシンプルなもの。
文法自体がリスト構造になっているのを意識する。
if, for , while などの制御構文が用意されている。
関数(proc)も活用できる。
ある程度、他のスクリプトに触れていればすんなり理解できる文法だと思います。ただ、expectコマンド以外でこのTclをあつかう機会があるのかは疑問ですけどね・・。
expectコマンドを使う際にシェルスクリプト内に記述して、
頑張ってエスケープしながら書いているケース多く見ます。
しかし、Tclで実現できる内容であれば、無理にシェルで処理は書かずに、tclスクリプトにして実行してあげる方がシンプルに書けると思います。
参考になれば幸いです。