Tera Term TTL脚本中子过程定义与调用方法

8 次阅读

Tera Term TTL(Tera Term Language)是一种专门用于终端自动化的脚本语言,常用于串口、Telnet、SSH等场景中的自动登录、命令发送、设备配置和批量测试。脚本规模较小时,将所有命令直接写在主流程中尚且容易维护,但当自动化任务逐渐复杂后,大量重复代码会让脚本难以阅读和修改。

TTL提供了子过程(Procedure)机制,可以将一组具有独立功能的操作封装起来,然后在主流程或其他过程内部重复调用。掌握proc、call、return等语法,是编写结构清晰、可复用Tera Term TTL脚本的重要基础。

Tera Term TTL子过程是什么

Tera Term TTL中的子过程可以理解为一个具有独立名称的代码块。它通常用于封装某一项重复任务,例如:

  • 登录设备;

  • 发送一组初始化命令;

  • 清理屏幕;

  • 执行设备配置;

  • 检查命令执行结果;

  • 记录测试信息;

  • 执行重复性的业务操作。

与简单地复制粘贴命令相比,子过程最大的优势是代码复用。某个操作需要调整时,只需要修改过程本身,所有调用位置都会使用新的逻辑。

典型的TTL子过程结构如下:

ttl
proc SendCommand
    sendln 'show version'
    wait '#'
return

调用时使用:

ttl
call SendCommand

执行到call语句后,TTL会进入对应的子过程;遇到return后,再返回到调用位置继续执行。

TTL子过程的基本定义语法

Tera Term TTL使用proc定义子过程,基本格式如下:

ttl
proc 过程名
    ; 子过程中的命令
    ...
return

例如定义一个发送设备状态查询命令的过程:

ttl
proc CheckStatus
    sendln 'show status'
    wait '#'
return

这里的CheckStatus就是过程名称。

调用:

ttl
call CheckStatus

执行流程可以理解为:

主程序
  ↓
call CheckStatus
  ↓
进入 CheckStatus
  ↓
执行 sendln
  ↓
执行 wait
  ↓
return
  ↓
回到 call 后面的代码

这种结构特别适合将复杂TTL脚本拆分成多个功能模块。

使用call调用TTL子过程

定义过程之后,需要通过call命令执行。

基本语法:

ttl
call 过程名

例如:

ttl
proc LoginDevice
    sendln 'username'
    wait 'Password:'
    sendln '123456'
    wait '#'
return

sendln 'login'
wait 'Username:'
call LoginDevice
sendln 'show version'

当执行到:

ttl
call LoginDevice

脚本会进入LoginDevice过程。

过程执行结束后,return将控制权交还给调用者,因此后面的:

ttl
sendln 'show version'

仍然会继续执行。

需要注意,call调用的过程通常需要已经被TTL解释器识别。如果脚本中存在多个过程,建议按照清晰的结构组织代码,避免因为过程位置、脚本流程设计不合理而造成维护困难。

子过程参数的定义与传递

TTL子过程不仅可以执行固定命令,还可以接收参数,从而提高代码复用程度。

例如:

ttl
proc SendText
    sendln params
return

调用时可以传入参数:

ttl
call SendText 'hello'

子过程中的params可以获取调用时传入的参数。

如果需要传递多个参数,可以按照参数列表进行设计。例如:

ttl
proc SendTwoCommands
    sendln params
    sendln param2
return

调用:

ttl
call SendTwoCommands 'show version' 'show status'

不过,实际编写参数化TTL过程时,应特别注意参数解析方式和字符串中空格、引号等特殊字符的影响。对于复杂参数,最好先通过简单案例验证TTL版本及具体运行环境的行为。

使用参数提高子过程复用能力

假设需要对多个设备执行相同的配置命令,与其写成:

ttl
sendln 'interface eth0'
sendln 'description server1'

sendln 'interface eth1'
sendln 'description server2'

可以考虑把重复逻辑封装为过程。

例如:

ttl
proc ConfigInterface
    sendln 'interface'
    sendln 'description'
return

实际项目中,可以进一步结合参数、字符串拼接以及变量,实现更加灵活的命令生成。

参数化的核心思路是:

固定流程 + 可变化数据

固定的登录、等待、发送、检查流程放在子过程中,可变化的设备名称、接口名称、IP地址等作为参数传入。

这种方式能够明显减少重复代码。

子过程中的变量使用

TTL脚本中的变量可以与子过程配合使用。

例如:

ttl
username = 'admin'
password = '123456'

proc Login
    sendln username
    wait 'Password:'
    sendln password
return

调用:

ttl
call Login

这种方式适合封装登录逻辑。

不过需要区分变量本身与过程参数的使用场景。对于整个脚本都需要使用的配置数据,可以通过变量保存;对于只服务于某一次过程调用的数据,则更适合设计为过程参数。

这样可以降低不同代码模块之间的耦合。

子过程中使用wait进行结果判断

TTL自动化脚本中,一个常见问题是发送命令之后不能立即发送下一条命令,因为设备可能还没有返回结果。

因此子过程经常会将sendln和wait组合起来。

例如:

ttl
proc ShowVersion
    sendln 'show version'
    wait '#'
return

相比单纯发送:

ttl
sendln 'show version'
sendln 'show status'

加入等待条件之后,脚本可以根据设备返回的提示符继续执行。

对于登录过程,也可以这样组织:

ttl
proc Login
    sendln 'admin'
    wait 'Password:'
    sendln '123456'
    wait '#'
return

这样可以把完整的登录动作封装成一个独立模块。

通过子过程封装设备登录

实际自动化项目中,登录通常是最适合抽象成子过程的功能之一。

例如:

ttl
proc LoginDevice
    wait 'login:'
    sendln 'admin'
    wait 'Password:'
    sendln '123456'
    wait '#'
return

主流程只需要:

ttl
call LoginDevice

后续如果登录提示发生变化,例如设备从:

login:

改成:

Username:

只需要修改LoginDevice过程,不需要逐个修改主流程中的登录代码。

多个子过程组合使用

TTL脚本可以定义多个过程,将复杂任务拆成不同功能。

例如:

ttl
proc LoginDevice
    sendln 'admin'
    wait 'Password:'
    sendln '123456'
    wait '#'
return

proc GetVersion
    sendln 'show version'
    wait '#'
return

proc SaveConfig
    sendln 'save'
    wait '#'
return

主流程:

ttl
call LoginDevice
call GetVersion
call SaveConfig

这样的结构比将所有命令连续堆放在一个文件中更加容易理解。

可以按照功能形成类似的结构:

主流程
 ├── LoginDevice
 ├── GetVersion
 ├── CheckStatus
 ├── ConfigDevice
 └── SaveConfig

当脚本规模扩大时,这种模块化思路尤其重要。

子过程中再次调用其他子过程

子过程之间也可以形成调用关系。

例如:

ttl
proc LoginDevice
    sendln 'admin'
    wait 'Password:'
    sendln '123456'
    wait '#'
return

proc PrepareDevice
    call LoginDevice
    sendln 'enable'
    wait '#'
return

主程序:

ttl
call PrepareDevice

执行PrepareDevice时,会进一步调用LoginDevice。

这种方式可以构建多层次的自动化流程,但不建议设计过深的调用链。过程之间的依赖关系越复杂,调试时越难定位问题。一般情况下,让每个过程负责清晰、单一的任务会更容易维护。

return的作用与常见错误

return用于结束当前过程并返回调用位置。

例如:

ttl
proc TestConnection
    sendln 'ping 192.168.1.1'
    wait '#'
return

如果忘记写return,过程结束边界可能无法按照预期工作。

因此推荐保持完整结构:

ttl
proc ProcessName
    ; commands
return

不要把主程序代码和过程内容随意交叉排列。

另一个常见问题是误以为return只是普通的流程跳转命令。实际上,在子过程设计中,它承担的是“结束当前过程并返回调用者”的职责。

子过程与goto的区别

TTL同样支持流程跳转,因此有人会使用goto处理重复逻辑,但对于具有明确功能的代码块,过程通常更适合。

例如,下面这种结构:

ttl
goto Login

虽然可以实现流程跳转,但随着代码增加,很容易形成复杂的跳转关系。

相比之下:

ttl
call LoginDevice

能够直接表达“执行登录操作”的意图。

两者可以简单理解为:

方式主要用途
goto在脚本内部进行流程跳转
call调用一个已经定义的子过程
return从子过程返回调用位置

如果代码需要反复执行一套具有明确功能的操作,优先考虑使用proc + call + return进行封装。

TTL子过程设计中的实用技巧

子过程并不是越多越好。合理拆分才能真正提高脚本质量。

一个过程尽量只负责一个任务

例如:

ttl
proc LoginDevice
    ...
return

专门负责登录。

ttl
proc BackupConfig
    ...
return

专门负责配置备份。

不要把登录、配置、日志记录和文件处理全部塞进一个超长过程。

给过程使用明确的名称

推荐:

ttl
call LoginDevice
call CheckVersion
call SaveConfig

不推荐:

ttl
call A
call Test1
call DoSomething

过程名称应该尽可能体现实际功能,方便后续维护。

将重复的wait逻辑统一封装

如果多个地方都需要等待设备提示符,可以把相关操作设计为统一流程,避免不同位置出现不一致的等待条件。

避免过程内部依赖过多外部状态

如果一个过程必须依赖大量全局变量才能工作,那么它的复用性会下降。能够通过参数传入的数据,可以优先考虑参数化。

一个较完整的TTL子过程示例

下面的示例展示登录、查询和配置保存等过程如何组合:

ttl
; 登录设备
proc LoginDevice
    sendln 'admin'
    wait 'Password:'
    sendln '123456'
    wait '#'
return

; 查询版本
proc CheckVersion
    sendln 'show version'
    wait '#'
return

; 保存配置
proc SaveConfig
    sendln 'save'
    wait '#'
return

; 主流程
call LoginDevice
call CheckVersion
call SaveConfig

实际使用时,应根据目标设备的登录提示符、命令提示符和命令执行结果调整wait条件。

如果设备执行命令后可能出现多种返回结果,还可以结合TTL的条件判断、超时控制等机制进一步增强脚本的可靠性。

常见问题排查

call提示找不到过程

首先检查过程名称是否完全一致,包括大小写和拼写。

例如定义:

ttl
proc LoginDevice

调用时却写成:

ttl
call LoginDevce

就会产生问题。

过程执行后没有继续运行

重点检查过程末尾是否正确使用了:

ttl
return

同时检查过程内部是否存在等待条件一直无法满足的情况。

参数传递结果异常

如果过程需要接收字符串参数,应重点检查调用时的引号、空格以及参数解析方式。复杂字符串不要直接假设解析结果符合预期,最好使用实际TTL环境进行测试。

wait一直等待

很多所谓“子过程调用失败”的问题,实际上发生在过程内部的wait。

例如:

ttl
wait '#'

但目标设备实际提示符是:

>

那么脚本会一直等待#,看起来就像call没有返回。

排查时可以先确认设备实际返回内容,再调整等待条件。

Tera Term TTL子过程的推荐组织方式

对于规模较大的自动化脚本,可以按照“主流程 + 功能过程”的思路组织:

ttl
; ===== 功能过程 =====

proc LoginDevice
    ...
return

proc CheckDevice
    ...
return

proc ConfigDevice
    ...
return

proc SaveDevice
    ...
return


; ===== 主流程 =====

call LoginDevice
call CheckDevice
call ConfigDevice
call SaveDevice

这种写法能够让主流程非常直观,阅读脚本时可以快速了解整体执行顺序,而具体实现细节则隐藏在对应过程内部。

对于需要长期运行和维护的Tera Term自动化项目,还可以进一步按照登录、设备检测、配置、日志、异常处理等职责划分过程,使TTL脚本逐渐形成类似模块化程序的结构。

掌握proc定义、call调用以及return返回,是Tera Term TTL脚本实现模块化的基础。结合参数、变量、sendln、wait和条件判断后,可以将重复性的终端操作封装成可复用功能,从而减少重复代码,提高脚本的可读性、稳定性和维护效率。