RM-BLOG

IT系技術職のおっさんがIT技術とかライブとか日常とか雑多に語るブログです。* 本ブログに書かれている内容は個人の意見・感想であり、特定の組織に属するものではありません。/All opinions are my own.*

【UNIX】Tera Termマクロ(ttl)のメモ

TeraTermマクロ(.ttl)を使う機会があったので少し勉強した。
備忘のためそのメモを載せる。

Tera Termでサーバに接続してから行う一連の動作を「.ttl」というファイルに専用の文法で記述することでマクロ化することができる。
Tera Termの作者のページにリファレンスが載っている。


 

 
ttl文法:接続方法
「connect」という関数を使う。

connect '192.168.0.100:22 /ssh /v /auth=password /user=testuser /passwd=password'

192.168.0.100のホストにユーザー名:testuser、パスワード:passwordにて接続しろという指示。



ttl文法:コマンド発行(sendlnとwait)
「sendln」という関数を使う。

sendln 'ls -las'
wait #10 #13

接続したホストで「ls -las」を投げろという指示。
重要なのは「sendln」の部分だけ。
なのでコマンド実行にあたって「wait #10 #13」は不要。

この「sendln」は”投げたら投げっぱなし”なところがあり(バックグラウンドで投げて速攻先に進むイメージ)、
この例でいえば「ls -las」を実行したら結果が返ってこない間に先に(次の行に)進むようになっている。
ls程度の軽いコマンドならともかく、重いコマンドになると結果を受け止めない段階で先に進んでしまい、
後述するログに出力する情報が不足していたりして残念なことになるので、
コマンド実行後には「wait #10 #13」で「ホストから改行コード(#10(LF)か#13(CR))が送られて来るまで待つ」というのを一応念のためつけている。
ただ、lsでいえば複数行の戻り値があると1行目でwaitの判定は抜けてしまうので、正直気休めにしかならない。
ある程度の時間を見越してその間滞留させるというのもあるが、その間に直前のコマンドが終わるかどうかはわからないので、これも確実な方法ではない。
なので正直あまり複雑なコマンドを投げるのには適していない。
(というのは個人的に使いこなせていないからなのだろうが…)

waitにはタイムアウト設定が存在しており、厳密には「引数に渡された文字列が来るまでn秒間待つ」という動きをしている。
この「n秒」の部分はttl内で予約的に使用されている「timeout」という変数で管理されていて、
wait実行直前に故意の値を代入してやればその通りに動く。

timeout=3
wait 'aaa'

この例だと、「wait 'aaa'」で"aaa"が来るまで3秒間停止する。
普通"aaa"は来ないので(このあたりもあいまいなところだが)3秒ここで待機してそのまま先に進む。
直前のコマンドの終了判定のやり方がよくわからなかったので、
個人的にはいつもこういうやり方で(この程度待てば直前のコマンドは終わってるだろうという前提のもとで)実行制御をしていた。
もう少しスマートなやり方はありそうなものだが。

なお、これだけだとコマンドの実行結果はどこの記録にも残らないので、
結果(標準出力や標準エラー出力)をlogファイルに書き出す(後述)ような実装とペアにして使うほうが実用的だろう。



ttl文法:ログファイル設定
「logopen」「logclose」という関数を使う。

logopen 'D:\hogehoge\test.log' 0 1

「logopen」の後ろに出力先ログファイル名を記述(この例では「D:\hogehoge\test.log」)すると
以降の動作はそのログファイルに記述されるようになる。
Tera Termの操作ログ記録と多分同じ。
なお、後半の「0 1」は忘れた。(多分appendかどうかの記述だったと思う)

ログを閉じる場合は↓

logclose

ログファイル名の記述は不要。



ttl文法:変数定義
shの中で宣言するのと同じかんじで定義できる。

var='192.168.0.100'

この例だと変数「var」に"192.168.0.100"という文字列を代入したことを指す。

ちなみに変数名と「=」の間、さらに値の間にはスペースいれてもいいらしい。

var = '192.168.0.100'

↑でも同じ意味。



ttl文法:文字列操作(文字列結合)
「strconcat」という関数を使う。

var='192.168.0.100'
strconcat var ':22 /ssh /v /auth=password /user=testuser /passwd=password'

この例だと、
変数「var(="192.168.0.100"が代入済)」に、文字列":22 /ssh /v /auth=password /user=testuser /passwd=password"を結合しろ、という指示になる。
結合の文字列="192.168.0.100:22 /ssh /v /auth=password /user=testuser /passwd=password"は変数「var」に代入される。

これを使い、
ホスト名やユーザー名部分を外部から引き渡した引数で可変にする等の動作が可能になる。
「外部から引き渡した変数」云々は後述。



ttl文法:文字列操作(文字列複製、切り出し)
「strcopy」という関数を使う。

var='abcdefg'
strcopy 1 5 var2


この例だと変数「var」に代入されている文字列"abcdefg"の、1文字目から5文字目を変数「var2」にコピーしろ、という指示になる。
つまりこの操作の後、変数「var」には文字列"abcde"が代入されたことになる。

よって、全体をコピーしたい場合は「strlen」を使って文字列長を取って、
1からそこまでをコピー、というように指示する形になる。

var='abcdefg'
strlen var
len=result
strcopy 1 len var2

この例では、「strlen var」で変数「var」の文字列長を取得して、結果を変数「len」に代入(len=resultがそれに相当)。
strcopyで1からlenまでを指定することで文字列全体をコピーする動きを実現している。

ここで登場する「result」というのはttl内の予約語みたいなものらしく、
直前に実行したコマンドの結果を受け取るときに使用する特殊な変数になっている。
strlen関数の場合は渡された変数の文字列長が結果に格納されている。



ttl文法:文字列操作(文字列検索)
「strscan」関数を使う。結果は↑でも書いた「result」から受け取る。

var='testuser/password'
strscan var '/'
idx=result

この例では、変数「var」に代入された文字列"testuser/password"から、文字列"/"を探せ、という指示なる。
見つかった場合、その文字位置が「result」に記録される。

これを使って外部から渡された引数を分解することが出来、実行時引数の削減に役立つ。
例えばこれなら"testuser/password"にユーザー名/パスワードという意味を持たせている前提で

var='testuser/password'
strscan var '/'
idx=result

strlen var
len2=result

strcopy var 1 len-1 user
strcopy var len+1 len2 pass

とすれば、一つの変数「var」から
"/"より手前(strcopy var 1 len-1)は変数「user」に、
"/"より後ろ(strcopy var len+1 len2)は変数「pass」に、
それぞれ代入される。



ttl文法:日付・時刻の取得
「getdate」関数を使う。

getdate datetime '-%Y%m%d-%H%M%S'

この例では、現在日付を取得してそれを「-%Y%m%d-%H%M%S」の形式でフォーマットした後、変数「datetime」に代入しろ、という指示になる。
結果は「20141118-101920」(2014年11月18日10時19分20秒)という形になる。
前述したログファイルのファイル名なんかに使用すると便利だろう。



ttl文法:終わるときと注意事項
ttl実行を完了する場合はsendlnに"exit"を渡せばよい…

sendln 'exit' 

…のだが、これをした後もTera Termのプロセスが残り続けることがある。
これはTera Term側の設定で、
「設定」⇒「TCP/IP」⇒「自動的にウインドウを閉じる」にチェックが入っていない場合、プロセスが残ってしまう。
なので、ここのチェックをいれておくこと。



ttl実行方法
一連の動作を記録した「.ttl」ファイルを作成し、ローカル上に保存。
Windows端末である前提で、コマンドプロンプトから以下のように呼び出す。

@echo off

"D:\Program Files\teraterm\ttpmacro.exe" D:\hogehoge\test2.ttl 

pause

俺の端末に入ってるTera Termのインストール位置が「D:\Program Files\teraterm」だからこういう感じの書き方になるが、
Tera Termの実行exeが格納されているフォルダと同階層に「ttpmacro.exe」というのがあるので、
そいつを呼び出して引数に「.ttl」ファイルを渡す、という感じになる。

なお、この例は「.ttl」の実行そのものには引数がない設定になる。
後述するが、「.ttl」内に引数を渡すためにはさらにこの後ろに引数を並べる必要がある↓

"D:\Program Files\teraterm\ttpmacro.exe" D:\hogehoge\test2.ttl "testuser/password"

この例では、test2.ttlの実行に際して引数を一つ、"testuser/password"を渡している。



ttl文法:引数の受け取り
関数実行結果を記録する特殊変数「result」と同様に、引数を表す特殊変数「param2」「param3」というのが存在する。

var2=param2
var3=param3

「param2」は2番目の引数、「param3」は3番目の引数になる。

気を付けなくてはならないのは、
上述したコマンドプロンプトからの実行例では第一引数に既に「D:\hogehoge\test2.ttl」を使っているので、 ttlファイル内で扱える引数は2番目以降になるということである。
つまり

"D:\Program Files\teraterm\ttpmacro.exe" D:\hogehoge\test2.ttl "testuser/password"

↑のように実行した時
1番目の引数=D:\hogehoge\test2.ttl
2番目の引数=testuser/password
となる。
ttlファイル自身を指す1番目の引数はttl内では別に必要としない(はず)で、
実際の実行制御に必要なのは2番目以降の引数=param2以降、ということになる。



ttl文法:分岐
ifが使える。

var=1

if var=1 then
    strconcat var '1'
else
    strconcat var '2'
endif


判定分は「var=1」で代入表記と一緒だが混在しないように。



ttl文法:コメント
半角セミコロン(;)を行頭につけると、その行はコメント行になる。

; 暫定対応
;strcopy 1 10 var
strcopy 1 9 var

どうでもいいけどこういうコメントは不安になるよね。



ttl記述例と実行例
例えばサーバに接続してdf -h(DISK使用量を標準出力するコマンド)を実行して出てくる、というのを作ってみる。
「df_test.ttl」を以下のように記述する。

; ①ホスト名を外部から受け取る
hostname=param2

; ②接続文字列を生成
concmd=':22 /ssh /v /auth=password /user=testuser /passwd=password'
strconcat hostname concmd

; ③接続
connect hostname

; ④ログファイル準備
getdate datetime '_%Y%m%d_%H%M%S'
logfile='D:\hogehoge\ttl'
strconcat logfile datetime
strconcat logfile '.log'
logopen logfile 0 1

; ⑤dfコマンド実行
sendln 'df -h'

; ⑥脱出
timeout=3
wait'aaa'
sendln 'exit'

; ⑦ログファイル閉じる
logclose


で、「df_test.ttl」を外部から実行する「df_test_macro_exec.bat」を以下のように作成する。

@echo off

setlocal

echo ホストIPを入力
set /p IPADDR=

"D:\Program Files\teraterm\ttpmacro.exe" df_test.ttl "%IPADDR%"

pause



df_test_macro_exec.batを実行し、標準入力からホストのIPアドレスを入力させ、
そのIPアドレス宛てに接続を行い「df -h」を実行して戻ってくる簡単なマクロ。
IPアドレスの存在チェック、体系チェックとかはしていないので、わかっているなら直接書き込んだ方が良いだろう。
一つの実装例ということで。