Tclの使い方
- 1 Tcl(Tool Command Language)とは?
- 2 検証環境
- 3 インストール方法
- 4 putsコマンドの使い方
- 5 getsコマンドの使い方
- 6 setコマンドの使い方
- 7 制御コマンドの使い方
- 8 引数の使い方
- 9 関数の使い方
- 10 stringコマンドの使い方
- 11 日時を表示する方法
- 12 外部コマンドを実行する方法(exec)
- 13 配列の使い方
- 14 リストの使い方
- 15 ファイル操作
- 16 変数の有効範囲
- Y その他(sourceコマンドの使い方)
- Z 参考情報
1 Tcl(Tool Command Language)とは?
ソフトウェアのテスト工程を自動化するために、Tclとexpectについて調査しました。この記事では、Tclの使い方をまとめています。Tclはスクリプト言語で、「ティクル」と発音します。一方、Expectはリモートシステムとの対話的なプログラムを自動化するためのプログラムです。ExpectのスクリプトからTclを呼び出して、処理を実行します。Expectについては、別途記事を作成する予定です。
2 検証環境
AlmaLinux版数は以下のとおりです。
[root@server ~]# cat /etc/redhat-release AlmaLinux release 8.6 (Sky Tiger)
カーネル版数は以下のとおりです。
[root@server ~]# uname -r 4.18.0-372.9.1.el8.x86_64
3 インストール方法
tclパッケージをインストールします。
[root@server ~]# dnf -y install tcl
tclパッケージの版数を確認します。
[root@server ~]# rpm -qa|grep tcl tcl-8.6.8-2.el8.x86_64
4 putsコマンドの使い方
putsコマンドは文字列を標準出力やファイルに出力するコマンドです。
標準出力に文字列を出力するスクリプトを作成します。
[root@server ~]# vi test.exp [root@server ~]# cat test.exp #!/usr/bin/tclsh puts "Hello world!" puts stdout "Hello world!!"
スクリプトを実行すると、標準出力に文字列が出力されていることがわかります。
[root@server ~]# ./test.exp Hello world! Hello world!!
5 getsコマンドの使い方
getsコマンドは、標準入力からユーザーが入力した文字列を取得するコマンドです。
標準入力からユーザーが入力した文字列をsetコマンドで変数strに設定したあと、putsコマンドで変数strの内容を標準出力に繰り返し出力するスクリプトを作成します。
[root@server ~]# vi test.exp [root@server ~]# cat test.exp #!/usr/bin/tclsh while {1} { set str [gets stdin] puts stdout $str }
スクリプトを実行すると、キーボードから入力した111,222が標準出力に出力されていることがわかります。スクリプトを終了するには、Ctrl+cを押下します。
[root@server ~]# ./test.exp 11111 <= キーボードから111を入力する 11111 22222 <= キーボードから222を入力する 22222 ^C
6 setコマンドの使い方
setコマンドは変数に値を設定するコマンドです。
変数varに設定した文字列を標準出力に出力するスクリプトを作成します。
[root@server ~]# vi test.exp [root@server ~]# cat test.exp #!/usr/bin/tclsh set var 123 puts $var set var abc puts $var
スクリプトを実行すると、変数varに設定した文字列(123,abc)が表示されていることがわかります。
[root@server ~]# ./test.exp 123 abc
7 制御コマンドの使い方
7.1 if,else,elseifの使い方
7.1.1 ifコマンドの使い方
変数varの値が1なら、oneと表示するスクリプトを作成します。
[root@server ~]# vi test.exp [root@server ~]# cat test.exp #!/usr/bin/tclsh set var 1 if {$var == "1"} { puts "one" }
スクリプトを実行すると、oneと表示されていることがわかります。
[root@server ~]# ./test.exp one
7.1.2 elseコマンドの使い方
lindexコマンドはリストから要素を取り出すためのコマンドです。lindex $argv 0は第1引数を示します。引数に1を指定するとone、1以外を指定するとothersと表示するスクリプトを作成します。
[root@server ~]# vi test.exp [root@server ~]# cat test.exp #!/usr/bin/tclsh set var [lindex $argv 0] if {$var == "1"} { puts "one" } else { puts "others" }
スクリプトを実行すると、引数に1を指定するとone、1以外を指定するとothersと表示されていることがわかります。
[root@server ~]# ./test.exp 1 one [root@server ~]# ./test.exp 2 others [root@server ~]# ./test.exp 3 others
7.1.3 elseifコマンドの使い方
引数に1を指定するとone、2を指定するとtwo、1,2以外を指定するとothersと表示するスクリプトを作成します。
[root@server ~]# vi test.exp [root@server ~]# cat test.exp #!/usr/bin/tclsh set var [lindex $argv 0] if {$var == "1"} { puts "one" } elseif {$var == "2"} { puts "two" } else { puts "others" }
スクリプトを実行すると、引数に1を指定するとone、2を指定するとtwo、1,2以外を指定するとothersと表示されていることがわかります。
[root@server ~]# ./test.exp 1 one [root@server ~]# ./test.exp 2 two [root@server ~]# ./test.exp 3 others
7.2 whileの使い方
setコマンドでdateの実行結果を変数xに設定したあと、putsコマンドで変数xの値を出力します。そして、1秒スリープします。これを繰り返すスクリプトを作成します。
[root@server ~]# vi test.exp [root@server ~]# cat test.exp #!/usr/bin/tclsh while {1} { set x [exec date] puts $x after 1000; }
スクリプトを実行すると、1秒間隔で時刻が表示されていることがわかります。Ctrl+cを押下してスクリプトを終了します。
[root@server ~]# ./test.exp 2023年 4月 4日 火曜日 20:21:59 JST 2023年 4月 4日 火曜日 20:22:00 JST 2023年 4月 4日 火曜日 20:22:01 JST ^C
8 引数の使い方
以下の変数を使って、引数を確認するスクリプトを作成します。
・$argv0:スクリプトの名前
・$argc:引数の個数
・$argv 0:第1引数を示す。lindexを使って第1引数を返します。
・$argv 1:第2引数を示す。lindexを使って第2引数を返します。
[root@server ~]# vi test.exp [root@server ~]# cat test.exp #!/usr/bin/tclsh puts $argv0 puts $argc puts [lindex $argv 0] puts [lindex $argv 1]
スクリプトを実行すると以下のことがわかります。
・スクリプトの名前:test.exp
・引数の個数:2
・第1引数:111
・第2引数:222
[root@server ~]# ./test.exp 111 222 ./test.exp 2 111 222
9 関数の使い方
スクリプトの[ ]引用符はコマンド置換子です。[ ]で挟まれたリストはコマンドラインとみなされ、その実行結果がひとつのアーギュメントとしてコマンドに渡されます。
[root@server ~]# vi test.exp [root@server ~]# cat test.exp #!/usr/bin/tclsh set x 1 set y 2 proc add {x y} { puts x=$x,y=$y return [expr $x + $y] } set ret [add 1 2] puts x+y=$ret
スクリプトを実行します。
[root@server ~]# ./test.exp x=1,y=2 x+y=3
10 stringコマンドの使い方
10.1 大文字/小文字を区別する方法(string compare)
stringコマンドのcompareオプションを使って、大文字/小文字を区別するスクリプトを作成します。
[root@server ~]# vi test.exp [root@server ~]# cat test.exp #!/usr/bin/tclsh set var [lindex $argv 0] if ![string compare $var "aaa"] { puts "equal" } else { puts "not equal" }
スクリプトを実行すると、スクリプトへの引数がaaaならequal、AAAならnot equalと表示されていることがわかります。
[root@server ~]# ./test.exp aaa equal [root@server ~]# ./test.exp AAA not equal
10.2 大文字/小文字を区別しない方法(string compare -nocase)
stringコマンドのcompareオプションに-nocaseを指定して、大文字/小文字を区別しないスクリプトを作成します。
[root@server ~]# vi test.exp [root@server ~]# cat test.exp #!/usr/bin/tclsh set var [lindex $argv 0] if ![string compare -nocase $var "aaa"] { puts "equal" } else { puts "not equal" }
スクリプトを実行すると、引数がaaaでもAAAでもequalと表示されていることがわかります。
[root@server ~]# ./test.exp aaa equal [root@server ~]# ./test.exp AAA equal
10.3 ファイルから文字列を読み込む方法
テスト用のファイルを作成します。
[root@server ~]# vi sample.txt [root@server ~]# cat sample.txt 192.168.3.10 server 192.168.3.20 client
ファイルの終端(eof)まで1行ずつ変数fdに読み込み、それを標準出力に出力するスクリプトを作成します。
#!/usr/bin/tclsh set filename "sample.txt" set fd [open $filename] while {! [eof $fd]} { gets $fd line puts stdout $line } close $fd
スクリプトを実行すると、テスト用ファイルの中身が表示されていることがわかります。
[root@server ~]# ./test.exp 192.168.3.10 server 192.168.3.20 client
10.4 文字列を分割する方法
splitコマンドに空白とハイフンをデリミッタにして文字列を分割するスクリプトを作成します。
[root@server ~]# vi test.exp [root@server ~]# cat test.exp #!/usr/bin/tclsh set src "000 111 222" set dst [split $src " "] puts [lindex $dst 0] puts [lindex $dst 1] puts [lindex $dst 2] set src "333-444-555" set dst [split $src "-"] puts [lindex $dst 0] puts [lindex $dst 1] puts [lindex $dst 2]
スクリプトを実行します。
[root@server ~]# ./test.exp 000 111 222 333 444 555
11 日時を表示する方法
様々なフォーマットで時刻を表示するスクリプトを作成します。
[root@server ~]# vi test.exp [root@server ~]# cat test.exp #!/usr/bin/tclsh set systemTime [clock seconds] puts "Year with 4 digits is [clock format $systemTime -format %Y]" puts "Month number(01-12) is [clock format $systemTime -format %m]" puts "Day of month is [clock format $systemTime -format %d]" puts "Hour(00-23) is [clock format $systemTime -format %H]" puts "Minutes(00-59) is [clock format $systemTime -format %M]" puts "Seconds(00-59) is [clock format $systemTime -format %S]" puts "Now is [clock format $systemTime -format %Y/%m/%d,%H:%M:%S]"
スクリプトを実行します。
[root@server ~]# ./test.exp Year with 4 digits is 2023 Month number(01-12) is 04 Day of month is 05 Hour(00-23) is 20 Minutes(00-59) is 13 Seconds(00-59) is 10 Now is 2023/04/05,20:13:10
12 外部コマンドを実行する方法(exec)
execは外部コマンドの実行結果を返すコマンドです。たとえば、ls等のOSのコマンドを実行して、ファイル一覧を返すことができます。
12.1 時刻を表示する方法
setコマンドでdateの実行結果を変数xに設定して、putsコマンドで変数xの値を出力するスクリプトを作成します。
[root@server ~]# vi test.exp [root@server ~]# cat test.exp #!/usr/bin/tclsh set x [exec date] puts $x
スクリプトを実行すると、dateの実行結果が表示されていることがわかります。
[root@server ~]# ./test.exp 2023年 4月 5日 水曜日 20:17:44 JST
12.2 ファイルを表示する方法
setコマンドでls -lの実行結果を変数xに設定して、putsコマンドで変数xの値を出力するスクリプトを作成します。
[root@server ~]# vi test.exp [root@server ~]# cat test.exp #!/usr/bin/tclsh set x [exec ls -l] puts $x
スクリプトを実行すると、ファイルの一覧が表示されていることがわかります。
[root@server ~]# ./test.exp 合計 1564 -rw-r--r--. 1 tcpdump tcpdump 252 3月 30 21:49 1.cap -rw-r--r--. 1 tcpdump tcpdump 312 3月 30 22:01 2.cap -rw-r--r--. 1 tcpdump tcpdump 140 3月 30 22:03 3.cap -snip-
12.3 カレンダーを表示する方法
カレンダーを表示するスクリプトを作成します。
[root@server ~]# vi test.exp [root@server ~]# cat test.exp #!/usr/bin/tclsh set x [exec cal] puts $x
スクリプトを実行すると、カレンダーが表示されていることがわかります。
[root@server ~]# ./test.exp 4月 2023 日 月 火 水 木 金 土 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30
13 配列の使い方
13.1 配列に値を代入/配列要素の値を表示する方法
setコマンドでxという名前の配列にaaa,bbb,cccを代入し、putsコマンドで配列の要素を表示するスクリプトを作成します。
[root@server ~]# vi test.exp [root@server ~]# cat test.exp #!/usr/bin/tclsh set x(0) aaa set x(1) bbb set x(2) ccc puts $x(0) puts $x(1) puts $x(2)
スクリプトを実行すると、配列xに代入した文字列が出力されていることがわかります。
[root@server ~]# ./test.exp aaa bbb ccc
13.2 配列の要素数を求める方法(array size)
[root@server ~]# vi test.exp [root@server ~]# cat test.exp #!/usr/bin/tclsh set x(0) aaa set x(1) bbb set x(2) ccc set n [array size x] puts "array has $n elements"
スクリプトを実行すると、配列の要素数が3であることがわかります。
[root@server ~]# ./test.exp array has 3 elements
13.3 配列が存在するかどうかを確認する方法(array exists)
配列が存在するかどうかを確認するスクリプトを作成します。配列が存在するかどうかはarrayコマンドのexistsオプションを使って確認します。配列が存在する場合は1,配列が存在しない場合は0を返します。
[root@server ~]# vi test.exp [root@server ~]# cat test.exp #!/usr/bin/tclsh set x(0) aaa set x(1) bbb puts $x(0) puts $x(1) puts "Does array exist? [array exists x]" array unset x puts "array is deleted by unset command" puts "Does array exist? [array exists x]"
スクリプトを実行します。
[root@server ~]# ./test.exp aaa bbb Does array exist? 1 array is deleted by unset command Does array exist? 0
13.4 指定した添字の要素を返す方法(array get)
arrayコマンドのgetオプションを使って、配列の要素を返すスクリプトを作成します。
[root@server ~]# vi test.exp [root@server ~]# cat test.exp #!/usr/bin/tclsh set x(0) aaa set x(1) bbb set x(2) ccc puts [array get x] puts [array get x 0] puts [array get x 1] puts [array get x 2]
スクリプトを実行します。
[root@server ~]# ./test.exp 0 aaa 1 bbb 2 ccc 0 aaa 1 bbb 2 ccc
13.5 2次元配列の使い方
スクリプトを作成します。
[root@server ~]# vi test.exp [root@server ~]# cat test.exp #!/usr/bin/tclsh set x(0,0) 10 set x(0,1) 20 set x(1,0) aa set x(1,1) bb for {set i 0} {$i < 2} {incr i} { for {set j 0} {$j < 2} {incr j} { puts $x($i,$j) } }
スクリプトを実行します。
[root@server ~]# ./test.exp 10 20 aa bb
13.6 連想配列の使い方
連想配列とは、文字列など非負整数以外のデータを添字に使用することができる配列のことです。
tokyo,osakaを添え字にした連想配列に文字列の代入、代入した文字列を表示するスクリプトを作成します。
[root@server ~]# vi test.exp [root@server ~]# cat test.exp #!/usr/bin/tclsh set x("tokyo") 14000000 set x("osaka") 8900000 puts $x("tokyo") puts $x("osaka")
スクリプトを実行します。
[root@server ~]# ./test.exp 14000000 8900000
14 リストの使い方
リストとは、中括弧あるいはダブルクォートを使ってスペースで区切られた文字列のことです。
setコマンドを使って変数xにリストを代入して、putsコマンドで変数xに設定されたリストの第1、第3要素を標準出力に出力します。そして、最後にリストの要素数を出力するスクリプトを作成します。
[root@server ~]# vi test.exp [root@server ~]# cat test.exp #!/usr/bin/tclsh set x {10 20 30} puts [lindex $x 0] puts [lindex $x 2] puts "The length of list x is [llength $x]"
スクリプトを実行すると、リストの第1、第3要素が表示されていることがわかります。また要素数が3であることもわかります。
[root@server ~]# ./test.exp 10 30 The length of list x is 3
15 ファイル操作
15.1 ファイルが存在するかどうかを確認する方法(file exists)
テスト用のファイルを作成します。
[root@server ~]# touch sample.txt [root@server ~]# ls sample.txt sample.txt
fileコマンドのexistsオプションを使って、カレントディレクトリにsample.txtが存在するかどうかを確認するスクリプトを作成します。
[root@server ~]# vi test.exp [root@server ~]# cat test.exp #!/usr/bin/tclsh if {[file exists sample.txt] == 1} then { puts "FOUND" } else { puts "NOT FOUND" }
スクリプトを実行すると、カレントディレクトリにsample.txtが存在するので、FOUNDと表示されていることがわかります。
[root@server ~]# ./test.exp FOUND
カレントディレクトリからテスト用ファイルを削除します。
[root@server ~]# rm sample.txt rm: 通常ファイル 'sample.txt' を削除しますか? y
再度、スクリプトを実行します。カレントディレクトリにsample.txtが存在しないので、NOT FOUNDと表示されていることがわかります。
[root@server ~]# ./test.exp NOT FOUND
15.2 ファイル名のドットまでの名前を返す方法(file rootname)
テスト用のファイルを作成します。
[root@server ~]# touch sample.tar.gz [root@server ~]# ls sample.tar.gz sample.tar.gz
fileコマンドのrootnameオプションを使って、最後のドットまでのファイル名を返すスクリプトを作成します。
[root@server ~]# vi test.exp [root@server ~]# cat test.exp #!/usr/bin/tclsh set x [file rootname sample.tar.gz] puts $x set y [file rootname $x] puts $y
スクリプトを実行します。
[root@server ~]# ./test.exp sample.tar sample
15.3 ディレクトリを作成する方法(file mkdir)
テスト用ディレクトリを確認します。testディレクトリが存在しないことを確認します。
[root@server ~]# ls -ld test ls: 'test' にアクセスできません: そのようなファイルやディレクトリはありません
fileコマンドのmkdirオプションを使って、ディレクトリを作成するスクリプトを作成します。
[root@server ~]# vi test.exp [root@server ~]# cat test.exp #!/usr/bin/tclsh set test_dir "/root/test" file mkdir $test_dir
スクリプトを実行すると、testディレクトリが作成されたことがわかります。
[root@server ~]# ./test.exp [root@server ~]# ls -ld test drwxr-xr-x. 2 root root 6 4月 5 22:01 test
16 変数の有効範囲
globalコマンドを使うことで、関数外の変数にアクセスすることができます。globalコマンドは、関数内で実行する必要があります。ここでは、関数test1内で変数xをグローバル変数として定義しています。
[root@server ~]# vi test.exp [root@server ~]# cat test.exp #!/usr/bin/tclsh set x 10 proc test1 {} { global x return $x } proc test2 {} { set x abc return $x } puts "The return value of test1 is [test1]" puts "The return value of test2 is [test2]"
スクリプトを実行します。
[root@server ~]# [root@server ~]# ./test.exp The return value of test1 is 10 The return value of test2 is abc
Y その他(sourceコマンドの使い方)
sourceコマンドは、外部のtclソースファイルを読み込むコマンドです。
source manual page - Built-In Commands
expectパッケージをインストールします。
[root@server ~]# dnf -y install expect
sourceコマンドで読み込むスクリプトを作成します。
[root@server ~]# vi proc.exp [root@server ~]# cat proc.exp proc test {} { puts "This is sample" }
スクリプトを作成します。
[root@server ~]# vi test.exp [root@server ~]# cat test.exp #!/usr/bin/expect source proc.exp test
スクリプトを実行します。
[root@server ~]# ./test.exp This is sample