RouterOS脚本语言手册,本手册介绍了 RouterOS 内置的强大脚本语言。
脚本可以存储在脚本存储库中,也可以直接写入控制台。用于触发脚本执行的事件包括但不限于系统计划程序、流量监视工具和 Netwatch 工具生成的事件。
如果您已经熟悉RouterOS中的脚本,则可能希望查看我们的提示和技巧。
生产线结构
RouterOS脚本分为许多命令行。命令行将逐个执行,直到脚本结束或发生运行时错误。
命令行
RouterOS 控制台使用以下命令语法:
RouterOS 控制台使用以下命令语法:
RouterOS 控制台使用以下命令语法:
[prefix] [path] command [uparam] [param=[value]] .. [param=[value]]
- [前缀] - “:”或“/”字符,指示命令是 ICE 还是路径。可能是必需的,也可能不是必需的。
- [路径] - 所需菜单级别的相对路径。可能是必需的,也可能不是必需的。
- 命令 - 指定菜单级别可用的命令之一。
- [uparam] - 未命名参数,如果命令需要,则必须指定它。
- [参数] - 命名参数序列,后跟相应的值
命令行的末尾由标记“;”或换行符表示。有时,“;”或换行符不需要结束命令行。
内部的单个命令不需要任何结尾的命令字符。命令的结束由整个脚本的内容决定`
(), [] or {}
:if ( true ) do={ :put "lala" }
另一个命令行中的每个命令行都以方括号“[ ]”(命令串联)开头和结尾。
:put [/ip route get [find gateway=1.1.1.1]];
请注意,上面的代码包含三个命令行:
:p ut
/ip route get
查找网关 = 1.1.1.1
可以通过遵循行连接规则从多个物理行构造命令行。
物理线路
物理行是由行尾 (EOL) 序列终止的字符序列。可以使用任何标准平台线端接序列:
- unix – ASCII LF;
- windows – ASCII CR LF;
- mac – ASCII CR;
可以使用新行字符的标准 C 约定(\n 字符)。
评论
注释以哈希字符 (#) 开头,在物理行的末尾结束。哈希符号之前不允许使用空格或任何其他符号。语法会忽略注释。如果 (#) 字符出现在字符串中,则不将其视为注释。
例
># this is a comment
# bad comment:global a; # bad comment:global myStr "lala # this is not a comment"
可以使用反斜杠字符 (\) 将两个或多个物理行连接成逻辑行。以反斜杠结尾的行不能带有注释。反斜杠不会继续注释。反斜杠不会继续标记,但字符串文本除外。反斜杠在字符串文本外的行上的其他位置是非法的。
例
:if ($a = true \ and $b=false) do={ :put “$a $b”; }:if ($a = true \ # bad comment
and $b=false) do={ :put “$a $b”; }# comment \
continued – invalid (syntax error)
令牌之间的空格
空格可用于分隔标记。仅当两个令牌的串联可以解释为不同的令牌时,才需要空格。例:
{
:local a true; :local b false; # whitespace is not required
:put (a&&b); # whitespace is required
:put (a and b); }
不允许使用空格字符
- 在’<参数>=’之间
- 在 ‘from=’ ‘to=’ ‘step=’ ‘in=’ ‘do=’ ‘else=’ 之间
例:
>#incorrect::for i from = 1 to = 2 do = { :put $i }#correct syntax::for i from=1 to=2 do={ :put $i }:for i from= 1 to= 2 do={ :put $i } #incorrect/ip route add gateway = 3.3.3.3#correct/ip route add gateway=3.3.3.3
范围
变量只能在脚本的某些区域中使用。这些区域称为作用域。作用域确定变量的可见性。有两种类型的作用域 - 和 。在块中声明的变量只能在该块和由该块包围的块内访问,并且只能在声明点之后访问。globallocal
全球范围
全局作用域或根作用域是脚本的默认作用域。它是自动创建的,无法关闭。
本地范围
用户可以定义自己的组来阻止对某些变量的访问,这些作用域称为局部作用域。每个局部作用域都括在大括号 (“{ }”) 中。
{
:local a 3;
{
:local b 4;
:put ($a+$b);
}#line below will show variable b in light red color since it is not defined in scope
:put ($a+$b);}
在上面的代码中,变量具有局部作用域,并且在闭合大括号后将无法访问。b
注意:写入终端的每一行都被视为本地范围
例如,定义的局部变量在下一个命令行中将不可见,并且将生成语法错误
[admin@MikroTik] > :local myVar a
[admin@MikroTik] > :put $myVarsyntax error (line 1 column 7)
警告:****不要在局部作用域内定义全局变量。
请注意,即使变量也可以定义为全局变量,除非尚未定义,否则它只能从其作用域中可用。
{
:local a 3;
{
:global b 4;
}
:put ($a+$b);}
上面的代码将生成错误。
关键字
以下单词是关键字,不能用作变量和函数名称:
and or in
分隔符
以下标记用作语法中的分隔符:
() [] {} : ; $ /
### 数据类型
RouterOS 脚本语言具有以下数据类型:
类型 | 描述 |
---|---|
num (number) | - 64位有符号整数,可能的十六进制输入; |
bool (boolean) | - 值可以是蜜蜂或true``false ; |
str (string) | - 字符序列; |
ip | - IP地址; |
ip-prefix | - IP 前缀; |
ip6 | - IPv6 地址 |
ip6-prefix | - IPv6 前缀 |
id (internal ID) | - 以“*”符号为前缀的十六进制值。每个菜单项都分配有唯一的编号 - 内部ID; |
time | - 日期和时间值; |
array | - 在数组中组织的值序列; |
nil | - 默认变量类型,如果未分配值; |
常量转义序列
以下转义序列可用于定义字符串中的某些特殊字符:
“ | 插入双引号 |
---|---|
\ | 插入反斜杠 |
\n | 插入换行符 |
\r | 插入回车符 |
\t | 插入水平选项卡 |
$ | 输出 用于链接变量。 |
? | 输出?字符。否则?用于在控制台中打印“帮助”。 |
_ | - 空间 |
\a | - 贝尔 (0x07) |
\b | - 退格键(0x08) |
\f | - 换行(0xFF) |
\v | 插入垂直选项卡 |
\xx | 从十六进制值打印字符。十六进制数字应使用大写字母。 |
例
:put "\48\45\4C\4C\4F\r\nThis\r\nis\r\na\r\ntest";
将显示在显示屏上 `HELLOThisisatest`
运营商
算术运算符
RouterOS 脚本语言中支持常用的算术运算符
算子 | 描述 | 例 |
---|---|---|
“+” | 二进制加法 | :put (3+4); |
“-“ | 二进制减法 | :put (1-6); |
“*“ | 二进制乘法 | :put (4*5); |
“/“ | 二进制除法 | :put (10 / 2); :put ((10)/2) |
“%” | 模运算 | :put (5 % 3); |
“-“ | 一元否定 | { :local a 1; :put (-a); } |
注意:要进行划分,您必须在红利周围使用大括号或空格,以免被误认为是IP地址
关系运算符
算子 | 描述 | 例 |
---|---|---|
“<” | 少 | :put (3<4); |
“>” | 大 | :put (3>4); |
“=” | 平等 | :put (2=2); |
“<=” | 小于或等于 | |
“>=” | 大于或等于 | |
“!=” | 不等于 |
逻辑运算符
算子 | 描述 | 例 | ||
---|---|---|---|---|
“!” | 逻辑 NOT | :put (!true); |
||
“&&” , “and” | 逻辑和 | :put (true&&true) |
||
“||” , “or” | 逻辑或 | `:put (true | false);` | |
“in” | :put (1.1.1.1/32 in 1.0.0.0/8); |
按位运算符
按位运算符正在处理数字,IP和IPv6地址数据类型。
算子 | 描述 | 例 | ||
---|---|---|---|---|
“~” | 位反转 | :put (~0.0.0.0) :put (~::ffff) |
||
“|” | 按位 OR。对每对对应位执行逻辑 OR 操作。在每对中,如果其中一个位或两个位均为“1”,则结果为“1”,否则结果为“0”。 | `:put (192.168.88.0 | 0.0.0.255):put (2001::1 | ::ffff)` |
“^” | 按位异或。与 OR 相同,但如果两个位不相等,则每个位置的结果是“1”,如果位相等,则为“0”。 | :put (1.1.1.1^255.255.0.0) :put (2001:1^:0) |
||
“&” | 按位和。在每对中,如果第一位和第二位是“1”,则结果为“1”。否则,结果为“0”。 | :put (192.168.88.77&255.255.255.0) :put (2001::1111&ffff::) |
||
“<<” | 按给定位数左移,IPv6 地址数据类型不支持 | :put (192.168.88.77<<8) |
||
“>>” | 按给定位数右移,IPv6 地址数据类型不支持 | :put (192.168.88.77>>24) |
使用“&”运算符计算给定IP和CIDR网络掩码的子网地址:
{:local IP 192.168.88.77;:local CIDRnetmask 255.255.255.0;:put ($IP&$CIDRnetmask);}
从给定的 IP 地址获取最后 8 位:
:put (192.168.88.77&0.0.0.255);
使用“|”运算符和倒置 CIDR 掩码计算广播地址:
{
:local IP 192.168.88.77;
:local Network 192.168.88.0;
:local CIDRnetmask 255.255.255.0;
:local InvertedCIDR (~$CIDRnetmask);
:put ($Network|$InvertedCIDR)
}
#### 串联运算符
算子 | 描述 | 例 |
---|---|---|
“.” | 连接两个字符串 | :put (“concatenate” . “ “ . “string”); |
“,” | 连接两个数组或将元素添加到数组 | :put ({1;2;3} , 5 ); |
可以在没有串联运算符的情况下向字符串添加变量值:
:global myVar "world";:put ("Hello " . $myVar);# next line does the same as above:put "Hello $myVar";
通过在字符串中使用 [] 和() 可以在字符串中添加表达式:
:local a 5;:local b 6;:put " 5x6 = $($a * $b)";:put " We have $[ :len [/ip route find] ] routes";
其他运营商
算子 | 描述 | 例 |
---|---|---|
“[]” | 命令替换。只能包含单个命令行 | :put [ :len "my test string"; ]; |
“()” | 子表达式或分组运算符 | :put ( "value is " . (4+5)); |
“$” | 替换运算符 | :global a 5; :put $a; |
“~” | 将值与 POSIX 扩展正则表达式匹配的二进制运算符 | 打印网关以 202 结尾的所有路由 /ip route print where gateway~"^[0-9 \\.]*202\$" |
“->” | 按键获取数组元素 | [admin@x86] >:global aaa {a=1;b=2} [admin@x86] > :put ($aaa->"a") 1 [admin@x86] > :put ($aaa->"b") 2 |
变量
脚本语言有两种类型的变量:
- global- 可从当前用户创建的所有脚本访问,由全局关键字定义;
- local- 只能在当前范围内访问,由本地关键字定义。
注意:从 v6.2 开始,可以有未定义的变量。当变量未定义时,解析器将尝试查找设置的变量,例如,通过DHCP或热点lease-script on-login
注意:可变值大小限制为 4096 字节
除内置的 RouterOS 变量外,每个变量都必须在使用本地或全局关键字之前声明。未定义的变量将被标记为未定义,并将导致编译错误。例:
# following code will result in compilation error, because myVar is used without declaration:set myVar "my value";:put $myVar
正确代码:
:local myVar;:set myVar "my value";:put $myVar;
例外情况是使用设置的变量,例如,通过 DHCP 设置lease-script
/system script
add name=myLeaseScript policy=\
ftp,reboot,read,write,policy,test,winbox,password,sniff,sensitive,api \
source=":log info \$leaseActIP\r\
\n:log info \$leaseActMAC\r\
\n:log info \$leaseServerName\r\
\n:log info \$leaseBound"
/ip dhcp-server set myServer lease-script=myLeaseScript
变量名称中的有效字符是字母和数字。如果变量名包含任何其他字符,则应将变量名放在双引号中。例:
#valid variable name:local myVar; #invalid variable name:local my-var; #valid because double quoted:global "my-var";
如果变量最初定义时不带值,则变量数据类型设置为 nil,否则数据类型由脚本引擎自动确定。有时需要从一种数据类型转换为另一种数据类型。它可以使用数据转换命令来实现。例:
>#convert string to array:local myStr "1,2,3,4,5";:put [:typeof $myStr];:local myArr [:toarray $myStr];:put [:typeof $myArr]
变量名称区分大小写。
:local myVar "hello"# following line will generate error, because variable myVAr is not defined:put $myVAr# correct code:put $myVar
不带值的 Set 命令将取消定义变量(从环境中删除,v6.2 中新增)
#remove variable from environment:global myVar "myValue":set myVar;
#### 保留的变量名称
所有内置的 RouterOS 属性都是保留变量。与 RouterOS 内置属性定义相同的变量可能会导致错误。为避免此类错误,请使用自定义名称。
例如,以下脚本将不起作用:
{
:local type "ether1";
/interface print where name=$type;
}
但将使用不同的定义变量:
{
:local customname "ether1";
/interface print where name=$customname;
}
命令
全局命令
每个全局命令都应以 “:” 标记开头,否则它将被视为变量。
命令 | 语法 | 描述 | 例 |
---|---|---|---|
/ | 转到根菜单 | ||
.. | 按一个菜单级别返回 | ||
? | 列出所有可用的菜单命令和简要说明 | ||
global | :global <var> [<value>] |
定义全局变量 | :global myVar "something"; :put $myVar; |
local | :local <var> [<value>] |
定义局部变量 | { :local myLocalVar "I am local"; :put $myVar; } |
beep | :beep <freq> <length> |
内置扬声器蜂鸣音 | `` |
delay | :delay <time> |
在给定时间段内不执行任何操作 | `` |
put | :put <expression> |
将提供的参数放到控制台 | `` |
len | :len <expression> |
返回字符串长度或数组元素计数 | :put [:len "length=8"]; |
typeof | :typeof <var> |
返回变量的数据类型 | :put [:typeof 4]; |
pick | :pick <var> <start>[<end>] |
元素或子字符串的返回范围。如果未指定结束位置,则 将仅返回数组中的一个元素。 | :put [:pick "abcde" 1 3] |
log | :log <topic> <message> |
将消息写入系统日志。可用主题包括"debug, error, info and warning" |
:log info "Hello from script"; |
time | :time <expression> |
返回执行命令所需的时间间隔 | :put [:time {:for i from=1 to=10 do={ :delay 100ms }}]; |
set | :set <var> [<value>] |
为声明的变量赋值。 | :global a; :set a true; |
find | :find <arg> <arg> <start> |
返回子字符串或数组元素的位置 | :put [:find "abc" "a" -1]; |
environment | :environment print <start> |
打印初始化的变量信息 | :global myVar true; :environment print; |
terminal | `` | 终端相关命令 | `` |
error | :error <output> |
生成控制台错误并停止执行脚本 | `` |
execute | :execute <expression> |
在后台执行脚本。结果可以通过设置参数写入文件。file | { :local j [:execute {/interface print follow where [:log info ~Sname~]}]; :delay 10s; :do { /system script job remove $j } on-error={} } |
parse | :parse <expression> |
解析字符串并返回解析的控制台命令。可用作功能。 | :global myFunc [:parse ":put hello!"];$myFunc; |
resolve | :resolve <arg> |
返回给定 DNS 名称的 IP 地址 | :put [:resolve "www.mikrotik.com"]; |
toarray | :toarray <var> |
将变量转换为数组 | `` |
tobool | :tobool <var> |
将变量转换为布尔值 | `` |
toid | :toid <var> |
将变量转换为内部 ID | `` |
toip | :toip <var> |
将变量转换为 IP 地址 | `` |
toip6 | :toip6 <var> |
将变量转换为 IPv6 地址 | `` |
tonum | :tonum <var> |
将变量转换为整数 | `` |
tostr | :tostr <var> |
将变量转换为字符串 | `` |
totime | :totime <var> |
将变量转换为时间 | `` |
菜单特定命令
常用命令
大多数子菜单中都提供以下命令:
命令 | 语法 | 描述 |
---|---|---|
add | add <param>=<value>..<param>=<value> |
添加新项目 |
remove | remove <id> |
删除所选项目 |
enable | enable <id> |
启用所选项目 |
disable | disable <id> |
禁用所选项目 |
set | set <id> <param>=<value>..<param>=<value> |
更改所选项目参数,一次可以指定多个参数。可以通过在参数前指定“!”来取消设置参数。 例: `/ip firewall filter add chain=blah action=accept protocol=tcp port=123 nth=4,2printset 0 !port chain=blah2 !nth protocol=udp``` |
get | get <id> <param>=<value> |
获取所选项目参数值 |
print <param><param>=[<value>] |
打印菜单项。输出取决于指定的打印参数。此处介绍了最常见的打印参数 | |
export | export [file=<value>] |
从当前菜单及其子菜单(如果存在)导出配置。如果指定了 file 参数,则输出将写入扩展名为“.rsc”的文件,否则输出将打印到控制台。导出的命令可以通过导入命令导入 |
edit | edit <id> <param> |
在内置文本编辑器中编辑所选项目属性 |
find | find <expression> |
返回与给定表达式匹配的项的内部编号列表。例如::put [/interface find name~"ether"] |
进口
导入命令可从根菜单获得,用于从导出命令创建或手动编写的文件中导入配置。
打印参数
有几个参数可用于打印命令:
参数 | 描述 | 例 |
---|---|---|
append | `` | |
as-value | 将输出打印为参数数组及其值 | :put [/ip address print as-value] |
brief | 打印简要说明 | `` |
detail | 打印详细说明,输出不如简要输出可读,但可用于查看所有参数 | `` |
count-only | 仅打印菜单项计数 | `` |
file | 将输出打印到文件 | `` |
follow | 打印所有当前条目并跟踪新条目,直到按下ctrl-c,在查看日志条目时非常有用 | /log print follow |
follow-only | 在按下 ctrl-c 之前仅打印和跟踪新条目,这在查看日志条目时非常有用 | /log print follow-only |
from | 仅从指定项目打印参数 | /user print from=admin |
interval | 以选定的时间间隔连续打印输出,有助于跟踪不可接受的更改follow |
/interface print interval=2 |
terse | 以紧凑和机器友好的格式显示细节 | `` |
value-list | 每行显示一个值(适合解析目的) | `` |
without-paging | 如果输出不适合控制台屏幕,则不要停止,一次性打印所有信息 | `` |
where | 表达式后跟可用于筛选出匹配条目的参数 | /ip route print where interface="ether1" |
一次可以指定多个参数,例如,/ip route print count-only interval=1 where interface="ether1"
循环和条件语句
循环
命令 | 语法 | 描述 |
---|---|---|
do..while | :do { <commands> } while=( <conditions> ); :while ( <conditions> ) do={ <commands> }; |
执行命令,直到满足给定条件。 |
for | :for <var> from=<int> to=<int> step=<int> do={ <commands> } |
在给定的迭代次数内执行命令 |
foreach | :foreach <var> in=<array> do={ <commands> }; |
为列表中的每个元素执行命令 |
条件语句
命令 | 语法 | 描述 |
---|---|---|
if | :if(<condition>) do={<commands>} else={<commands>} <expression> |
如果给定条件是然后执行块中的命令,否则在块中执行命令(如果指定)。true``do``else |
例:
{
:local myBool true;
:if ($myBool = false) do={ :put "value is false" } else={ :put "value is true" }}
功能
脚本语言不允许直接创建函数,但是您可以使用:p arse命令作为解决方法。
从 v6.2 开始,添加了新的语法,以便更轻松地定义此类函数,甚至传递参数。也可以使用 :return 命令返回函数值。
请参阅以下示例:
#define function and run it:global myFunc do={:put "hello from function"}$myFunc
output:hello from function#pass arguments to the function:global myFunc do={:put "arg a=$a"; :put "arg '1'=$1"} $myFunc a="this is arg a value" "this is arg1 value"output:arg a=this is arg a valuearg '1'=this is arg1 value
请注意,有两种方法可以传递参数:
- 传递具有特定名称的 arg(在我们的示例中为“a”)
- 传递值而不带 arg 名称,在这种情况下,arg “1”, “2” ..使用“n”。
返回示例
:global myFunc do={ :return ($a + $b)}:put [$myFunc a=6 b=2]output:8
您甚至可以从脚本环境中克隆现有脚本并将其用作函数。
#add script
/system script add name=myScript source=":put \"Hello $myVar !\""
:global myFunc [:parse [/system script get myScript source]]
$myFunc myVar=world
output:
Hello world !
警告:如果函数包含已定义的全局变量,其名称与传递的参数的名称匹配,则全局定义的变量将被忽略,以便与为旧版本编写的脚本兼容。此功能在将来的版本中可能会更改。避免使用与全局变量同名的参数。
例如:
:global my2 "123":global myFunc do={ :global my2; :put $my2; :set my2 "lala"; :put $my2 }$myFunc my2=1234:put "global value $my2"
输出将为:
1234lalaglobal value 123
嵌套函数示例
注意:要调用另一个函数,需要声明其名称(与变量相同)
:global funcB do={
:global funcA;
:return ([$funcA] + 4)}:put [$funcB]Output:9
捕获运行时错误
从 v6.2 开始,脚本能够捕获运行时错误。
例如,[code]:reslove[/code] 命令如果失败将引发错误并中断脚本。
[admin@MikroTik] > { :put [:resolve www.example.com]; :put "lala";}failure: dns name does not exist
现在我们要捕获此错误并继续使用我们的脚本:
:do {
:put [:resolve www.example.com];} on-error={ :put "resolver failed"};:put "lala" output:resolver failed
lala
阵列操作
警告:数组中的键名包含除小写字符以外的任何字符,应将其放在引号中
例如:
[admin@ce0] > {:local a { "aX"=1 ; ay=2 }; :put ($a->"aX")}1
遍历键和值
[admin@ce0] > :foreach k,v in={2; "aX"=1 ; y=2; 5} do={:put ("$k=$v")}0=21=5aX=1y=2
[admin@ce0] > :foreach k in={2; "aX"=1 ; y=2; 5} do={:put ("$k")}2512
注意:如果数组元素具有键,则这些元素按字母顺序排序,不带键的元素在具有键的元素之前移动,并且其顺序不会更改(请参阅上面的示例)。
更改单个数组元素的值
[admin@MikroTik] > :global a {x=1; y=2}[admin@MikroTik] > :set ($a->"x") 5 [admin@MikroTik] > :environment print
a={x=5; y=2}
脚本存储库
子菜单级别: /system script
包含所有用户创建的脚本。可以通过几种不同的方式执行脚本:
- on 事件 - 脚本在某些设施事件(调度程序、 网络监视、 VRRP)上自动执行)
- 由另一个脚本 - 允许在脚本内运行脚本
- 手动 - 从控制台执行运行命令或在 winbox 中
注意:只有具有相同或更高权限的脚本(包括调度程序、netwatch 等)才能执行其他脚本。
属性 | 描述 |
---|---|
comment (字符串;违约:) | 脚本的描述性注释 |
dont-require-permissions (是 | 否;默认值:否) | 在执行脚本时绕过权限检查,当从具有有限权限的服务(如 Netwatch)执行脚本时很有用 |
name (字符串;默认值:“脚本[编号]”) | 脚本的名称 |
policy (字符串;违约:) | 适用政策列表: ftp - 可以通过ftp远程登录,并从路由器发送和检索文件密码 - 更改密码策略 - 管理用户策略,添加和删除用户读取 - 可以检索配置重新启动 - 可以重新启动路由器敏感 - 允许更改“隐藏敏感”参数嗅探 - 可以运行嗅探器,火炬等测试 - 可以运行 ping、跟踪路由、带宽测试写入 - 可以更改配置在此处阅读更详细的政策说明 |
source (字符串;) | 脚本源代码 |
只读状态属性:
属性 | 描述 |
---|---|
last-started (日期) | 上次调用脚本的日期和时间。 |
owner (字符串) | 创建脚本的用户 |
run-count (整数) | 计算脚本执行次数的计数器 |
菜单特定命令
命令 | 描述 |
---|---|
run (运行 [id|name]) | 按 ID 或名称执行指定的脚本 |
环境
子菜单级别:
/system script environment
/environment
包含所有用户定义的变量及其分配的值。
[admin@MikroTik] > :global example;[admin@MikroTik] > :set example 123[admin@MikroTik] > /environment print
"example"=123
只读状态属性:
属性 | 描述 |
---|---|
name (字符串) | 变量名 |
user (字符串) | 定义变量的用户 |
value () | 分配给变量的值 |
工作
子菜单级别: /system script job
包含所有当前正在运行的脚本的列表。
只读状态属性:
财产 | 描述 |
---|---|
owner (字符串) | 正在运行脚本的用户 |
policy (数组) | 应用于脚本的所有策略的列表 |
started (日期) | 脚本启动的本地日期和时间 |
还没有评论,来说两句吧...