Teratermマクロの定石ってどうなのよ?
さすがにコマンド1行を送信するごとにプロンプトの表示を待つコードを挟むというやり方(そうしないとリモートの状況関係なく問答無用で送信するのでうまくコマンドが実行できない場合があるのですが…)はコマンド1つ2つならともかく増えてくるとちょっとどうかと思ってくるので、
あらかじめ作成しておいたシェルスクリプトを送ってリモート側(UNIX系OSを想定)で保存し、リモート側で実行するマクロを作ってみた。
SSH接続ならSFTPを使ってファイルを送るコマンドがあるのですが、Telnetだとそんなものは存在しないようなので工夫する必要がある。
Telnetでテキストファイルを送信するコード
;すでにtelnet接続に成功していると仮定
;プロンプトの内容は環境や設定によって変わるので適宜変更する
prompt = "localhost $"
;ローカルのファイルを1行ずつ読み込んでcatコマンドでリモートに書き込み
;ローカルから読み込むファイルがinput.sh、リモートに書き込んだファイルがoutput.shになっているので
;任意のファイル名に変更する。
wait prompt
fileopen fh input.sh 0
sendln "cat << TTLEOF > output.sh"
while 1
filereadln fh buf
if result=1 then
break
endif
sendln buf
endwhile
sendln "TTLEOF"
fileclose fh
;プロンプトの表示を待ってシェルスクリプトを実行
wait prompt
sendln "sh ./output.sh"
teratermマクロのファイルを1行ずつ読み込むfilereadlnコマンドと、シェルのヒアドキュメントを使い終端として指定した文字列がある直前の行までの複数行の文字列をcatで出力したものをファイルにリダイレクトするという方法を利用しています。
どういうこと?
ヒアドキュメントというのはざっくり言えば複数行にわたる文字列を文字列結合や特殊文字等を使うことなくそのまま表現するための記法のこと。
ヒアドキュメントがあれば複数行の文字列を表現するのにわざわざ\n
のような特殊文字を使ったり、改行部分でエスケープ文字を挟んだり、諦めて1行ごとに何度も同じ処理を繰り返し使う必要はないってことです。
UNIX系OSの一般的なシェルでは
コマンド << EOF
...
複数行にわたる文字列
...
EOF
でコマンドへの標準入力**(重要)**として複数行の文字列を渡すことができます。文字列の終わりを判別するために終端となる文字列(ここではEOF)を決める必要があります。終端の文字列はEOFに限らず任意の文字列にすることが可能です。
これをファイルの内容をそのまま標準出力へ出力(ファイルの指定がない場合は標準入力の内容を出力)するcatコマンドに渡し、
標準出力をファイルにリダイレクトすることでヒアドキュメントの内容をそのままファイルに書き込むことができるわけです。
# 2行目からEOFの直前の行までの文字列をtest.txtに書き込む
cat << EOF > test.txt
...
複数行にわたる文字列
...
EOF
teratermマクロ側からすればヒアドキュメントを標準入力にして任意のファイルにリダイレクトしているcatコマンド実行中の文字列送信はそのままヒアドキュメントの内容となるので、
あらかじめ決めておいた終端文字列を送信するまで送信した文字列の内容がそのままファイルに書き込まれることになります。
もっと詳しくわかりやすい解説はいくらでもネットに転がってるのでググってください。
応用
sendln buf
を
expandenv exbuf buf
sendln exbuf
としておくとローカル側の環境変数(例:%ENV%
)を展開してくれるようになります。
純粋なシェルスクリプトではなくなりますが、ローカルでバッチファイルと連携している場合は設定が共通化できるので便利です。
注意点
UTF-8は使えないというか事実上日本語は使えない
teratermマクロのfilereadlnコマンドはUTF-8に対応しておらず(2020年11月現在)、UTF-8のファイルを読み込もうとしてもうまく読み込んでくれません。
Shift-JISならいけるっぽいですが、リモート側がUNIX系OSなんかだとまたそれはそれで…という感じなので日本語は使えないと思っておいたほうがいいです。
送信するシェルスクリプト内でヒアドキュメントを使う場合は注意しよう
ファイルの書き込みにヒアドキュメントを使ってる関係上、teratermマクロ側で終端とした文字列と同じ文字列がシェルスクリプト内にあるとファイルの書き込みが途切れてしまいます。
最もありえそうなのがシェルスクリプト内でヒアドキュメントを使い終端文字列を同じものに設定した場合でしょうか。
一応上記のコードではTTLEOFとしているのでまぁ被ることはないとは思いますが、一応意識はしておきましょう。