目录
本章开始讲ros的脚本语法,主要是根据ros wiki文档脚本部分进行讲解。
本章讲ros的基础语法,命令行结构。后面几章讲解ros脚本的都是基于《RouterOS脚本实验实例pppoe配置》基础上进行讲解的
一、命令行语法
1.1 命令行语法
RouterOS控制台是使用下面的命令语法:
[前缀] [路径] 命令 [未命名参数] [参数=[值]] .. [参数=[值]]
- [前缀 ] – 如果命令是ICE或者路径通过":”或者"”字符表示[路径]–得到操作菜单的路径
- [路径 ] – 得到操作菜单的路径
- 命令 – 一个命令获取在指定的菜单路径下
- [未命名参数] – 即事先定义参数 ,如果命令需要必须指该即事先定义参数
- [参数 ] – 按先后顺序各自定义值 按先后顺序各自定义值
命令行结束符为“;”,它也可以代表换行。在结束命令行有时不需要“;”
或者换行独立的命令包含 (), [] 或者 {}不需要任何的结尾命令字符,命令结尾取决于脚本的内容
ps:如果你不确定除了大小小括号外命令行是否加分号结束符,最好还是加上。
1.2 关于大中小括号解说
上面没有对大小括号进行讲解对于没有接触过开发的初学者会有点懵,所以有必须讲一下
1.2.1 小括号:一个整体
小括代表是一个整体。那它具体用在哪里呢
- 优先级。当有几个操作的时候,会涉及到优先级,可能需要几个低优先级的结果再进行运算,这样低优先级的需要用小括号。运行符优先级将在后面讲,也可以自己搜索一下其它语言的优先级。如java语言运算符优先级,大部分是相同的,学完可以测试一下。ros运行符并不像java那样丰富,毕竟是脚本语言。
如:2+3的结果现乘以6,我们小学的时候就知道要用小括号括起来,在程序中就优先级问题,你可以写成“(2+3)*6”,但是你把小括号去掉那就有问题了 2+3*5变成了17而不是我们想要的30
- 易读性。当有几个操作虽然不加小括号,优先级没有变化,但是不方便阅读啊!
如:k = (j>i) && (8==i); 你完全可以写成 “k = j>i && 8==i;",但是这样方便阅读吗,别人还要特意运行一下看是不是和自己理解一样,有时还要查一下优先级表!影响他人的工作效率。
1.2.2 中括号:子命令
中括号表达里填写的是ros命令,中括号会返回执行命令结果,这样就可以把结果变参数的值。
比如要在pppoe的在线用户名,查名为p11用户在线时长
分析:
查在线用户可以在ppp active
要查某个字段,可以使用get,但是get必须要指定项目号。如果直接填写项目号不妥,因为项目号是变的,所以要结合find命令,find命令刚才能找到项目号,具体命令如下:
[hua@MikroTik] > :put [ppp active get number=[ find where name=p11] value-name=uptime] 00:43:15
上面中“:put”表示输出, number=[ find where name=p11] value-name=uptime 的意思是把find找到的结果项目号赋值给get的number参数
注:中括号命令可以写相对路径,也可以写绝对路径,上面的就是相对路径,和前面的命令是同等级,这里前面的命令是get,所以get的上一级命令下所有都是同等的,可以直接使用。
1.2.3 花括号:语句块
当我们要的结果一个命令执行不了,需要多个命令才行,那么我们就要用花括号括起来,还有条件和循环语句,后面将会讲解。
比如:如果找到p11用户,则把上网时间,发到计费平台上(实际操作中可以直接用freeradius的数据库中查,推荐使用mysql),
如果发送可以使用fetch命令,我这里就不用了,使用打印“发送平台成功”来表示
如果用winbox创建脚本并写下代码,如下:
代码如下:
# 获取p11用户在线时间,并赋值给本地变量userUptime # 当一条命令太长的时候,可以使用 "\"行连接符 :local userUptime [/ppp active get number=\ [find where name=p11] value-name=uptime] # 如果变量的值大于0,则判断用户存在,可以用fetch把用户时间的值提以get或post方式交到平台 # 在这里我简单一点直接选择打印 # 如果变量为空,即不是大于0,则表示用户没有找到 :if ($userUptime>0) do={ :put $userUptime :put "sucess" } else={ :put "user not foud!" }
可以使用如下命令查看运行结果:
[hua@MikroTik] > system script run sendUserUptime 02:39:25 sucess
二、注解:方便你我
2.1 注解说明
一个注释从“#”号字符开始执行,并结束在一行的结尾,空格或者任何其他标示不允许在#标示之前。如果“#”字符出现在一个字符串中将不会考虑为一个注释内容。
为什么要用到注解,当我们写脚本代码或开发的时候,适当地给代码添加注解可以方便理解,如果共同开发的话,其他人阅读你的代码也会提高理解
PS:一般项目都要求写项目说明文档,在小公司中经常赶项目,也有不少人的项目不会写项目文档,尤其是几任换下来,新来的没有项目说明文档只能看源代码,如果源代码写得很乱,一点说注解说明都没有,那是一件很痛苦的事。
所以养好写注解、写项目说明文档的好习惯吧^_^
2.2 例子
例子我就不说了,上面最前面有#号的就是,#号一般是放在行首的,最前面。
# 1.判断用户是否存在 :if ($userUptime>0) do={ # 2.前面有空格,不推荐的注解 :put $userUptime # 3.行末,不推荐的注解位置 :put "sucess" } else={ :put "user not foud!" }
第2和第3种注解是不推荐的,在我的ros6.47中这个注解也是没有问题的,其实为在编程中我喜欢用直接在代码对应的顶部进行注解,跟着代码的缩进而缩进
三、行连接:提升阅读性
当我们写一个ros命令的时候,这个命令很长,为了提高阅读性,美观,我们会建议适当地把代码分行,那分了行怎么告诉ros我这个是同一行的呢?那就要用到行连接符,这里使用的是 "\"
比如我在前面写的
:local userUptime [/ppp active get number=\ [find where name=p11] value-name=uptime]
PS:请记住一句:代码的可阅读性很重要!
当然生产环境的代码为了节约空间可以不美化,使用压缩。比如jquery分开发版本和生产环境版本,开发版就是美化的,文件会大一点,而开发版是压缩的,把空格换行注解等能去掉的都全部去掉!
四、指令之间的空格
4.1 说明
空格可以用于分隔指令。仅当两个指令挨一起会产生另一个意思或误解,需要空格把它隔开。
还有一部分是固定不充许有空格的
- 在 '< 参数 >=' >=' >=' >=' 之间不允许
- 在 'from=' 'to=' 'step=' 'in=' 'do=' 'else='这间不充许
4.2 例子
比如搞一个活动,给一些体验账号,前一个小时上网是免费的,当我们计费的时候就要判断用户在小且时长超过1小时才计费。
比如$IsUserOnline为用户是否在线,$userUptime为时长,为了方便测试我直接给变量赋值了,代码如下
:local IsUserOnline "true" :local userUptime "01:02:00" :if ($IsUserOnline=true&&$userUptime>"00:60:00")\ do={ :put "ok" } else={ :put "less than 1 hours" }
执行结果如下:
# 这个是用户存在,时间为1小时2分的 [hua@MikroTik] > system script run t1 ok # 我把userUptime 改为"00:32:00",再次执行效果 [hua@MikroTik] > system script run t1 less than 1 hours
这样写没什么毛病,如果if部分用and写变成"$IsUserOnline=true and $userUptime>"00:60:00" 这样也没问题,但是如果and前后没有空格那就有问题了,意思完全不同
变成这样"$IsUserOnline=trueand$userUptime>"00:60:00" ,在ros中没有报错,这样会产生误解啊,会变成是“$IsUserOnline=trueand”也不方便阅读
五、变量的作用域
5.1 什么是变量
在ros中可以粗暴理解为,把一些命令执行的结果及数据(如字符串、数字、IP地址等等)放在一个内存的“房间”中,这个“房间”就是来存各种ros数据。我们把这样的房间起个专业的名词叫变量。
PS:更专业的理解可以自行搜索一下。
内存中可以有很多变量,变量一般分为全局变量和局部变量
5.2 变量为分类
按作用域,即就是作用范围,可以分全局变量和局部变量。
值得注意的是变量是放在内存中的,除了系统释放和自己写的命释放外,重启、断电、关机再开都会导致变量消失。
5.2.1 全局变量
全局变量即是这个变量在整个ros中都可以使用。就相当于我们的公交车那样,大家都可以坐。
全局变量多使用可以跨脚本使用、因为大家都可以使用,个个都可以修改,所以使用全局变量时要很注意,如果脚本很多,改来改来,结果都不知道哪个脚本修改了。最后是人为的强制指定只有在特定的情况下才能使用
定义变量的格式为:
:global <变量名> <值>
获取变量的值为:“$变量名”
例子:在统计中如果在线用户数,很多个脚本在使用的话,那么可以把它设置为全局变量,这样这些脚本都可以使用了。
:global onlineNum [/ppp active print count-only]
执行效果:
# 一般写在脚本中,我这里方便就直接使用命令行去执行
[hua@MikroTik] > :global onlineNum [/ppp active print count-only]
1
[hua@MikroTik] > :put $onlineNum
1
5.2.2 局部变量
局部变量好理解,只能作到局部,使用关键词“:local ”定义。格式为:
:local <变量名> <值>
局部变量一般出现下面几个位置
- 在脚本:只能脚本内生效,出了这个脚本就失效。
- 中括号内:只在[]内有效,出了[]将失效
- 花括号内:只在{}内有效,出现{}失效
注:在命令行中,只能使用全局变量
例子:建立一个脚本为t1,输入下面内容
# 脚本内的变量,只在本脚本内生效
:local hello "ros"
# 2个字符串之间使用点号.连接
:put ($hello.",welcome")
# 局部变量在中括号[]内,超出中括号失效
[:local hello1 "() var";put $hello1]
# 失效,打印为空
:put $hello1
{:local hello2 "{} var";put $hello2}
# 失效,打印为空
:put $hello2
执行效果如下:
[hua@MikroTik] > system script run t1
ros,welcome
() var
() var
{} var
六、关键词
所谓的关键词就是ros系统指定有特殊含的词不能用作变量。比如 and(与)、or(或)、in(在...里)等等,这些都是有特殊含义的。
七、分隔符
下面记号作为分隔符的语法:
() [] {} : ; $ /
PS:什么是分隔符这就不用讲了吧,就是能起分隔作用的符号