【初心者必見】Tera Termマクロで「思った通りに動かない…」を防ぐ!受信バッファの仕組みと flushrecv 使用のおすすめ
こんにちは!インフラ周りの保守やキッティング自動化に触れる中で、先輩方が作成した膨大なTera Termマクロ(.ttl) をメンテナンスする機会が増えてきました。
一見シンプルに見えるTTLスクリプトですが、自分で新しく組んでみたりループ処理を入れたりすると、**「なぜか3回目の出力ではなく1回目の古いデータが取れてしまう」「アラームが出ていないはずなのにエラー処理に分岐してしまう」**といった、謎の挙動にすごく悩まされました……。
今回、(半分泣きながら
)debugを繰り返す中で 「Tera Termマクロが裏側で持っている受信バッファの仕組み」 を理解することが実は必要だったということに気づきました。
これを知るだけでマクロの安定性が劇的に向上したので、自分自身の備忘録も兼ねて情報をみなさんに共有させていただきたいと思います。少しでもお役に立てれば嬉しいです!
1. 文字列待ち受け(wait系)の裏側で起きていること
”基礎は重要”と先人は言っておりました。
まず、wait やwaitln といった関数がどのように文字列を見つけているのか、その仕組みを改めて確認しました。(基本過ぎてタイパが悪い?いえいえ。真逆でした。。)
1-1. ttermpro.exe と ttpmacro.exe の関係
実は、画面に見えているTera Term本体(ttermpro.exe)が受信した文字列は、そのままマクロ実行エンジン(ttpmacro.exe)に転送され、マクロ側の**「受信バッファ」**というメモリ領域に一時的に蓄積されます。
1-2. バッファ読み出しの基本ルール
wait などのコマンドが実行されると、この受信バッファを**「先頭から1文字ずつ順番に」**走査していく仕様になっています。

-
ターゲット文字列が見つかった場合: ヒットした位置までのバッファがクリア(破棄)され、システム変数
resultに1が格納されます。 -
見つからなかった場合: 指定したタイムアウト時間が経過するまで、あるいはバッファが溢れるまで、その文字列はバッファ内にずっと残り続けます。
この「見つからなかったら残り続ける」「先頭から順に走査する」という挙動が、数々の怪奇現象を引き起こす原因になっていました。
2. 私がハマった「2つのバッファトラップ」
自分が過去にやらかした原因を分析してみました。
(反省より前に分析~考えること。これ重要。)
トラップ①:ループ処理における「過去ログの残留」~誤検知
10秒ごとに3回 show memory を実行し、3回目の計測時間(Read Time)だけを取得してポップアップさせたい、というような処理がありました。(事例説明のため、本番macroより一部分抜出/シンプル加工でご紹介します。)
【原因の深掘り】
マクロが waitin で待ち受ける前に、1回目〜3回目の出力がすでに受信バッファにすべて流れ込んでしまっています。
その後、満を持して waitin 'Read Time' が走ると、エンジンはバッファの先頭から検索を始めるため、1回目のループで受信した古い Read Time を検知して正常終了してしまいます。これが誤検知の原因でした。
トラップ②:エコーバック(送出したコマンド自体)を誤認する
log中に alarm という文字列が含まれる場合だけ、ポップアップ(&パトランプ制御)を出したいという仕様がありました。
# show alarm minor
2026/06/10 16:18:55 Major IF1 startup error alarm
が、logをクリアしても、どんな場合でもalarm有りと誤検知してしまう不幸が・・・。
(結果パトランプが回りまくり。)
✕ 失敗していたコード
sendln 'show alarm minor'
wait 'alarm'
if result=1 then
messagebox 'alarm exist' 'info'
endif
これは受信バッファには送出するコマンド文字列も格納されるため発生した問題でした。

TelnetやSSHの通信では、こちらが送出したコマンド文字列(show alarm minor)自体も、機器側からエコーバックとしてそのまま返ってきて受信バッファに格納されます。
つまり、機器側でアラームが0件であっても、自分が送ったコマンド内の alarm という文字列に wait 関数が反応してしまい、result=1(検知成功)になってポップアップが出てしまうという盲点でした。
3. 回避テクニック素案
これらのバッファ起因の誤動作を防ぐために、とても勉強になった対策を2点ご紹介します!
対策1:適切なタイミングでの flushrecv のインジェクション
欲しいデータが送られてくる直前にflushrecvコマンドを実行し、バッファを明示的に空(フラッシュ)にします。
10秒毎に計3回実施し、3回目の計測時間させるという場合は下記のようにカウント値を調査し、ゴミ掃除。
以降に入ってきた文字列だけを奇麗に読み取るという作戦です。

対策2:ユニーク性の高いロングパターンやワイルドカード(*)の活用
単なる '200' などの短い文字列で待つと、送出コマンド内の数値や関係ないログに誤反応するため、プロンプトや後続のステータスまで含めて厳密にホールドします。
; '200' だけで待つと、送出コマンド内の '200' に誤反応してしまう
; 後続のステータス文字まで含めてユニークにして安全性を高める
wait '200 search success'
あるいは、ファイルシステム情報を調べるような場合は、ワイルドカード(*)をうまく組み合わせてコマンドを送ることで、エコーバックに引っかからない工夫をする手法も。
; 例:wait 'IMAGE.DAT' を狙う場合
sendln 'file ls IMAGE.*'
; コマンドのエコーバックは 'IMAGE.*' になるので、
; 本体の出力である 'IMAGE.DAT' にだけ wait を正確にヒットさせられます
wait 'IMAGE.DAT'
4.各種自動化macroに適用してみよう
折角なので、誤検知を避ける工夫を既存のmacroにも仕込んでみました。
何か送る前にはflushrecv。これ鉄則。
サンプル1:Palo Alto 装置状態取得macro
flushrecv
sendln ''
pause 1
wait 'admin@'
flushrecv
sendln 'set cli pager off'
pause 1
wait 'admin@'
flushrecv
sendln 'show system info'
pause 1
wait 'admin@'
flushrecv
sendln 'show system environmentals'
pause 1
wait 'admin@'
flushrecv
sendln 'show system disk-space'
pause 1
wait 'admin@'
sendln ''
サンプル2:Palo Alto 初期設定macro
flushrecv
sendln ''
pause 1
wait 'admin@'
flushrecv
sendln 'configure'
pause 1
wait 'admin@'
flushrecv
sendln 'set deviceconfig system ip-address 192.168.1.1 netmask 255.255.255.0 default-gateway 192.168.1.254'
pause 1
wait 'admin@'
flushrecv
sendln 'set deviceconfig system domain-lookup-url 1.1.1.1 locale ja timezone Asia/Tokyo ntp-servers primary-ntp-server ntp-server-address ntp.nict.jp'
pause 1
wait 'admin@'
flushrecv
sendln 'set deviceconfig system dns-setting servers primary 1.1.1.1'
pause 1
wait 'admin@'
flushrecv
sendln 'commit force'
pause 1
まとめ
これまで「なんか動かないから pause を多めに入れておこう…」と感覚で調整していたのですが、ttpmacro.exe の内部バッファの挙動をしっかり理解したことで、flushrecv は単なるおまじないではなく、「生存データとバッファを意図的にリセットするための超重要コマンド」なんだと一つ利口になりました!
なお、今回は割愛してしまいましたが、別問題を起因とした「受信バッファの読み込み位置ポインタが内部でどう進み、どう破綻するか
」といったものもあります。
そのあたりの仕組みももっとマニアックに深掘りしたい!という興味のある同士(?)がいらっしゃいましたら、コメント等でご連絡いただければ資料をお送りいたします!
もし同じようにTera Termマクロの謎の挙動で夜も眠れない方がいれば、ぜひこのバッファマネジメントを試してみてください。
最後まで読んでいただき、ありがとうございました!少しでも参考になったら「いいね」をいただけると励みになります!



