mcpField
R
routeros-scripting

routeros-scripting

github.com/tikoci开发8367 次安装5 天前更新
代码仓库

关于 routeros-scripting

routeros-scripting 是编写 RouterOS 脚本和 CLI 配置的参考技能,面向生成或审查 RouterOS 命令的人员。它聚焦语言特有的易错点,如临时行号、数组处理和权限要求。

主要功能

  1. 01RouterOS 语法与脚本编写指导
  2. 02运行时选择配置对象
  3. 03正确处理 find 结果与输出
  4. 04变量、数组和文件处理提示
  5. 05检查脚本策略与命令有效性

适用场景

  1. 01编写调度器或钩子使用的 RouterOS 脚本
  2. 02生成针对特定对象的配置
  3. 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:它允许权限较低的调用方以脚本自身的策略集运行脚本。仅将其用于权限范围经过明确限制的脚本。

运行前验证命令格式

对于不熟悉的属性、标志和依赖软件包的命令:

  1. 优先查阅新版 MikroTik 手册 CLI Reference: https://manual.mikrotik.com/docs/CLI%20Reference/
  2. 对于正在运行的路由器或特定 RouterOS 版本,/console/inspect 是权威依据。请参阅 routeros-command-tree 技能。
  3. 如果可用,请在执行前使用 rosetta MCP(routeros_explain_command、 routeros_command_tree)进行只读说明。
  4. 如果不确定且有本地 CHR 可用,请在一次性实例上运行 quickchr exec <name> '<command>' 再发布脚本。

优先查阅的官方文档

评论

支持 Markdown