关于 routeros-scripting
routeros-scripting 是编写 RouterOS 脚本和 CLI 配置的参考技能,面向生成或审查 RouterOS 命令的人员。它聚焦语言特有的易错点,如临时行号、数组处理和权限要求。
主要功能
- 01RouterOS 语法与脚本编写指导
- 02运行时选择配置对象
- 03正确处理 find 结果与输出
- 04变量、数组和文件处理提示
- 05检查脚本策略与命令有效性
适用场景
- 01编写调度器或钩子使用的 RouterOS 脚本
- 02生成针对特定对象的配置
- 03检查脚本中的 RouterOS 特有错误
安装
复制下面的命令,在终端中运行。
npx skills add https:/ / github.com/ tikoci/ routeros-skills --skill routeros-scripting安装后在 Claude Code 中输入/routeros-scripting确认已加载。
附带文件references/syntax.md
详细介绍
RouterOS 脚本与 CLI 配置
RouterOS 脚本(.rsc、/system/script、调度器 on-event、Netwatch 钩子以及交互式 CLI 代码片段)使用 RouterOS 自有语言。它不是 shell、Lua、Python 或 Tcl。语法基础请参阅 references/syntax.md。
本技能重点介绍大模型容易自信地弄错的陷阱。
不要在脚本中使用交互式行号
交互式 print 输出会显示当前控制台缓冲区中的临时行号(0、1、2……)。这些不是稳定的对象 ID,也不能在脚本中使用。
# WRONG in scripts — "1" is only an interactive print-buffer row number
/ip/route/set 1 gateway=3.3.3.3
# Better — internal IDs have a * prefix, but can change if objects are removed/re-added
/ip/route/set *1 gateway=3.3.3.3
# Best — resolve the target at runtime
/ip/route/set [find dst-address="0.0.0.0/0"] gateway=3.3.3.3
生成配置时,请使用 comment=、name= 或唯一地址/列表值等稳定选择器。内部 ID 可在 print as-value 中以 .id=*HEX 的形式查看。
将 [find] 的结果视为 ID 数组
[find ...] 会返回零个、一个或多个内部 ID。许多命令都可直接接受该数组(set、remove、disable),但需要精确获取一个对象的代码应在 get 前检查数量。
:local ids [/interface/find where name="ether1"]
:if ([:len $ids] = 1) do={
:put [/interface/get ($ids->0) name]
} else={
:error ("expected exactly one interface, got " . [:len $ids])
}
使用 [find comment="my-tool-tag"] 执行幂等清理,不要使用 [find dynamic=no] 这类宽泛选择器,以免删除无关的用户配置。
在 find/where 中为 IP 前缀加引号
RouterOS 会进行激进的类型转换,但转换方向并不总是符合预期。对于 /ip/address,address 属性以包含前缀长度的字符串形式存储。未加引号的字面值(如 111.111.1.1/24)会被视为 IP 前缀值,可能无法匹配任何内容。
# WRONG — can silently return nothing
/ip/address/print where address=111.111.1.1/24
# Correct
/ip/address/print where address="111.111.1.1/24"
# Correct when value came from a variable
:local prefix 111.111.1.1/24
/ip/address/print where address=[:tostr $prefix]
如果查询意外返回空结果,请检查存储的类型:
:put [:typeof ([:pick [/ip/address/print as-value] 0]->"address")]
print as-value 通常会返回映射数组
即使只匹配一行,print as-value where ... 也会返回 {{...}; {...}}。访问属性前,请先选取一行。
# WRONG — tries to read "gateway" from the outer array
:put ([/ip/route/print as-value where gateway="ether1"]->"gateway")
# Correct — pick the first map, then read the property
:put ([:pick [/ip/route/print as-value where gateway="ether1"] 0]->"gateway")
对于不支持 get 的命令,as-value 往往是唯一适合脚本使用的输出:
:put ([/tool/fetch url="https://example.com/file.txt" output=user as-value]->"data")
监控命令需要 once do={...}
除非指定只运行一次,否则 monitor-traffic 等命令会以交互式循环方式运行。在脚本中使用 once do={} 来捕获这些临时值。带连字符的字段名使用 $"name-with-hyphens"。
/interface/monitor-traffic ether1 once do={
:put ("rx=" . $"rx-bits-per-second")
}
对于没有终端连接的调度器或钩子脚本,请使用 :log,不要只用 :put。
在读取全局变量时必须重新声明
全局变量和全局函数不会自动在其他脚本或函数体中可见。读取或调用前,请使用 :global name; 声明访问权限。
:global state "ready"
:global showState do={
:global state
:put ("state=" . $state)
}
:global addOne do={ :return ($1 + 1) }
:global caller do={
:global addOne
:return [$addOne 5]
}
请使用唯一的变量名。避免使用与 RouterOS 属性冲突的名称,例如 dst-address;如果必须访问这类变量,请使用带引号的变量语法($"dst-address")。
数组不是 JavaScript 数组
# Empty array: {} is a syntax error
:local arr [:toarray ""]
# Indexing and assignment use ->
:set ($arr->"name") "router1"
:put ($arr->"name")
字符串与数组使用 . 拼接时会按元素展开,除非先进行转换:
:local arr {"a"; "b"}
:put ("value=" . $arr) # two outputs: value=a and value=b
:put ("value=" . [:tostr $arr]) # one output: value=a;b
命名键会按字母顺序排序。未命名元素保留插入顺序,但会移到带键元素之前。
文件有 CLI 专属限制
RouterOS 没有直接的“创建空文件”或追加操作。文档中介绍的变通方法是先通过 print file=... 创建文件,再写入 contents=。
/file/print file=myFile
/file/set myFile.txt contents=""
追加内容时,请读取现有内容、拼接后再将整个文件写回。RouterOS 脚本不适合处理大型文件和二进制内容;条件允许时,请优先使用 /tool/fetch、REST、SCP/SFTP 或外部工具。
脚本策略也是正确性的一部分
调度器、Netwatch、PPP on-up 以及类似钩子会在策略权限有限的情况下执行。如果脚本需要文件、备份、密码、嗅探或重启权限,调用方必须具备相应策略。
/system/script/add name=backup policy=read,write,ftp,sensitive source={
/system/backup/save name=daily
}
谨慎使用 dont-require-permissions=yes:它允许权限较低的调用方以脚本自身的策略集运行脚本。仅将其用于权限范围经过明确限制的脚本。
运行前验证命令格式
对于不熟悉的属性、标志和依赖软件包的命令:
- 优先查阅新版 MikroTik 手册 CLI Reference: https://manual.mikrotik.com/docs/CLI%20Reference/
- 对于正在运行的路由器或特定 RouterOS 版本,
/console/inspect是权威依据。请参阅routeros-command-tree技能。 - 如果可用,请在执行前使用
rosettaMCP(routeros_explain_command、routeros_command_tree)进行只读说明。 - 如果不确定且有本地 CHR 可用,请在一次性实例上运行
quickchr exec <name> '<command>'再发布脚本。
优先查阅的官方文档
- 新版 RouterOS 手册主页:https://manual.mikrotik.com/ — 将逐步取代旧版基于 Confluence 的
help.mikrotik.com文档。 - 脚本技巧: https://manual.mikrotik.com/docs/Developer%20Guides/Scripting/scripting-tips-and-tricks/
- 脚本示例: https://manual.mikrotik.com/docs/Developer%20Guides/Scripting/scripting-examples/
- CLI Reference: https://manual.mikrotik.com/docs/CLI%20Reference/ — 可按软件包和命令路径浏览命令/属性架构。