‹ 首页

routeros-scripting

@tikoci · 收录于 1 周前

RouterOS scripting language and CLI configuration idioms for .rsc files and interactive commands. Use when: writing or reviewing RouterOS scripts, scheduler/netwatch/on-event snippets, idempotent CLI config, :local/:global/:foreach/:do syntax, [find] selectors, print as-value handling, script permissions, or when the user mentions .rsc, RouterOS script, scripting tips, or CLI config automation.

适合你,如果经常管理 MikroTik 路由器并需要自动化配置

/ 下载安装
routeros-scripting.skill双击,或拖进 Claude 桌面版 / Cowork,即完成安装↓ .skill↓ .zip
用别的 agent?下载 .zip 解压,把文件夹放进它的技能目录
Claude Code~/.claude/skills/(项目级 .claude/skills/)
Codex CLI~/.codex/skills/
Cursor自动读取上面两处目录
其他工具见其文档的「skills」目录;两个下载是同一份文件,只是名字不同
/ 通过 npx 安装 校验哈希
npx oh-my-skill add tikoci/routeros-skills/routeros-scripting
/ 通过 bash 安装
curl -fsSL https://oh-my-skill.com/install.sh | bash -s -- tikoci/routeros-skills/routeros-scripting
/ 已经装过?验证本机副本,不用重装
npx oh-my-skill verify tikoci/routeros-skills/routeros-scripting
安装目标可用 --agent / --scope 或 --to 明确指定;省略时只会在唯一已存在的 agent 目录上自动选择,零命中或多命中会停止并提示。content_hash 缺失或不一致均拒装。
33GitHub stars
~1.7K最小装载
~4.4K含声明引用
~4.4K文本包总量
镜像托管

怎么用

技能原文 SKILL.md作者撰写 · MIT · 30e966c

RouterOS Scripting & CLI Config

RouterOS scripts (.rsc, /system/script, scheduler on-event, Netwatch hooks, and interactive CLI snippets) use RouterOS's own language. It is not shell, Lua, Python, or Tcl. For the syntax baseline, see [references/syntax.md](./references/syntax.md). This skill focuses on the traps that LLMs are likely to confidently get wrong.

Do Not Use Interactive Row Numbers in Scripts

Interactive print output shows temporary row numbers (0, 1, 2...) for the current console buffer. They are not stable object IDs and are not usable inside scripts.

# 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

For generated config, use stable selectors such as comment=, name=, or a unique address/list value. Internal IDs are visible in print as-value as .id=*HEX.

Treat [find] Results as ID Arrays

[find ...] returns zero, one, or many internal IDs. Many commands accept that array directly (set, remove, disable), but code that needs exactly one object should check the count before 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])
}

Use [find comment="my-tool-tag"] for idempotent cleanup, not broad selectors such as [find dynamic=no] that can delete unrelated user configuration.

Quote IP Prefixes in find / where

RouterOS does aggressive type conversion, but not always in the direction you expect. For /ip/address, the address property is stored as a string including the prefix length. An unquoted literal like 111.111.1.1/24 is an IP-prefix value and may match nothing.

# 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]

When a query unexpectedly returns nothing, inspect the stored type:

:put [:typeof ([:pick [/ip/address/print as-value] 0]->"address")]
print as-value Is Usually an Array of Maps

print as-value where ... returns {{...}; {...}}, even when only one row matches. Pick a row before accessing a property.

# 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")

For commands without get, as-value is often the only script-friendly output:

:put ([/tool/fetch url="https://example.com/file.txt" output=user as-value]->"data")
Monitor Commands Need once do={...}

Commands such as monitor-traffic are interactive loops unless told to run once. Use once do={} to capture their temporary values in a script. Hyphenated field names use $"name-with-hyphens".

/interface/monitor-traffic ether1 once do={
  :put ("rx=" . $"rx-bits-per-second")
}

Use :log, not only :put, for scheduler or hook scripts where no terminal is attached.

Globals Must Be Re-Declared Where Read

Global variables and global functions are not automatically visible inside another script or function body. Declare access with :global name; before reading or calling them.

: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]
}

Use unique variable names. Avoid names that collide with RouterOS properties such as dst-address; if you must access such a variable, use quoted variable syntax ($"dst-address").

Arrays Are Not JavaScript Arrays
# Empty array: {} is a syntax error
:local arr [:toarray ""]

# Indexing and assignment use ->
:set ($arr->"name") "router1"
:put ($arr->"name")

String concatenation with . distributes over arrays unless you convert first:

:local arr {"a"; "b"}
:put ("value=" . $arr)          # two outputs: value=a and value=b
:put ("value=" . [:tostr $arr]) # one output: value=a;b

Named keys are sorted alphabetically. Unnamed elements preserve insertion order but are moved before keyed elements.

Files Have CLI-Specific Limits

RouterOS has no direct "create empty file" or append primitive. The documented workaround creates a file via print file=..., then writes contents=.

/file/print file=myFile
/file/set myFile.txt contents=""

To append, read the existing contents, concatenate, and write the whole file back. Large files and binary content are a poor fit for RouterOS scripts; prefer /tool/fetch, REST, SCP/SFTP, or external tooling when possible.

Script Policies Are Part of Correctness

Scheduler, Netwatch, PPP on-up, and similar hooks execute with limited policies. If a script needs files, backups, passwords, sniffing, or reboot rights, the caller must have the matching policy.

/system/script/add name=backup policy=read,write,ftp,sensitive source={
  /system/backup/save name=daily
}

Be cautious with dont-require-permissions=yes: it allows less-privileged callers to run the script with the script's own policy set. Use it only for deliberately bounded scripts.

Validate Command Shape Before Running

For unknown attributes, flags, and package-dependent commands:

  1. Prefer the new MikroTik manual CLI Reference: <https://manual.mikrotik.com/docs/CLI%20Reference/>
  2. For a live router or exact RouterOS version, /console/inspect is the ground truth. See the routeros-command-tree skill.
  3. When available, use rosetta MCP (routeros_explain_command, routeros_command_tree) for read-only explanation before execution.
  4. If uncertain and a local CHR is available, use quickchr exec <name> '<command>' on a disposable instance before publishing the script.
Official Docs to Review First
  • New RouterOS manual home: <https://manual.mikrotik.com/> — replaces the older Confluence-based help.mikrotik.com documentation over time.
  • Scripting tips and tricks: <https://manual.mikrotik.com/docs/Developer%20Guides/Scripting/scripting-tips-and-tricks/>
  • Scripting examples: <https://manual.mikrotik.com/docs/Developer%20Guides/Scripting/scripting-examples/>
  • CLI Reference: <https://manual.mikrotik.com/docs/CLI%20Reference/> — browsable command/property schema organized by package and command path.
按 MIT 许可原样转载,未经改动 · 在 GitHub 查看 →

评论

登录即可评论;带「已验证安装」的,是发布者名下有本店的安装或持有记录。