I've been using Mikrotik for a few years now and found myself using the same code multiple times.
Mikrotik CMD scripting doesn't support functions you can call from your scripts, so I decided to try and come up with a fairly easy way to implement this.
I'm posting here to get any comments / suggestions / feedback on this code. If all the kinks are worked out, hopefully others will be able to contribute their functions as well.
Note: Lua can handle functions within scripts, but isn't implemented as of RouterOS v2.x, v3.30, or v4.5. Also you could use multiple scripts passing global variables to/from them, but this requires that no other script use that same global variable. By "injecting" global variables into a function, this should make the functions more flexible and minimize global variable collisions.
Here it is:
Code: Select all
# Script name: Functions
# Functions script library
# Remember: ' $ ' (dollar sign), ' " ' (double-quote), and ' \ ' (backslash) must be escaped with preceding backslash '\' to when used in functions
# Function input array is passed from calling script using:
# string: ":local input \"<input1,input2,...>\"; "
# command output: ":local input [/path/to/command get <item property>];"
# Function output array is stored in function's local $output variable
# Functions should always end with ; (semi-colon) - this makes it easier when calling from another script
#
# Ex. To call MyFunc with input "1,2,3,4", storing function's output in global var MyOutput
# From calling script:
# Code
# /system script run "Functions"
# :global MyFunc
#
# :global MyOutput ""
# :local runFunc [:parse (":global MyOutput;" . \
# ":local input \"1,2,3,4\";" . \
# $MyFunc . \
# ":set MyOutput \$output")
# ]
# $runFunc
# End Code
#
# The global variable $MyOutput now contains an array of output values from function
# To display output:
# :put [:pick $MyOutput 0]
# :put [:pick $MyOutput 1]
# :put [:pick $MyOutput 2]
# :put [:pick $MyOutput ...]
# Functions
#------------
# RandomNumGen: Generates a fairly random number from date, time, mem-free, and cpu-load
# Input array: none
# Output array:
# 0 = number generated
:global RandomNumGen ":local output \"\"
:set output (\$output . [:pick [/system clock get date] 7 11])
:set output (\$output . [:pick [/system clock get date] 4 6])
:set output (\$output . [:pick [/system clock get time] 0 2])
:set output (\$output . [:pick [/system clock get time] 3 5])
:set output (\$output . [:pick [/system clock get time] 6 8])
:set output (\$output . [/system resource get free-memory])
:set output (\$output . [/system resource get cpu-load])
:set output [:tonum \$output]
:set output [:toarray \$output];"
# DateToNum: Converts a given date (mmm/dd/yyyy) to numeric date (yyyymmdd)
# Input array:
# 0 = string date "mmm/dd/yyyy"
# Output array:
# 0 = numeric date yyyymmdd
:global DateToNum " :local output \"\"
:set input [:toarray \$input]
:if ([:len \$input] > 0) do={
:local input1 [:tostr [:pick \$input 0]]
:local months [:toarray \"jan,feb,mar,apr,may,jun,jul,aug,sep,oct,nov,dec\"]
:local mon 0
:for x from=0 to=([:len \$months] - 1) do={
:if ([:tostr [:pick \$months \$x]] = [:tostr [:pick \$input1 0 3]]) do={
:if (\$x < 9) do={ :set mon (\"0\" . (\$x + 1)) } else={ :set mon (\$x + 1) } } }
:set output ([:pick \$input1 7 11] . \$mon . [:pick \$input1 4 6])
:set output [:tonum \$output]
:set output [:toarray \$output]
};"
# TimeToNum: Removes ':' from given time (hh:mm:ss) -> (hhmmss)
# Input array:
# 0 = string time "hh:mm:ss"
# Output array:
# 0 = numeric time hhmmss
:global TimeToNum " :local output \"\"
:set input [:toarray \$input]
:if ([:len \$input] > 0) do={
:local input1 [:tostr [:pick \$input 0]]
:for x from=0 to=([:len \$input1] - 1) do={
:if ([:tostr [:pick \$input1 \$x (\$x + 1)]] != \":\") do={
:set output (\$output . [:tostr [:pick \$input1 \$x (\$x + 1)]]) } }
:set output [:tonum \$output]
:set output [:toarray \$output]
};"
# RegExFind: Searches a given string for an exact regex pattern
# Input array:
# 0 = string regex search
# 1 = string regex pattern
# Output array:
# 0 = number start index of regex match (-1 if not found)
# 1 = number end index of regex match (-1 if not found)
:global RegExFind " :local output \"\"
:set input [:toarray \$input]
:if ([:len \$input] > 1) do={
:local input1 [:tostr [:pick \$input 0]]
:local input2 [:tostr [:pick \$input 1]]
:for x from=0 to=([:len \$input1] - 1) do={
:if ([:pick \$input1 \$x [:len \$input1]] ~ (\"^\" . \$input2)) do={
:for y from=\$x to=([:len \$input1] - 1) do={
:if ([:pick \$input1 \$x (\$y + 1)] ~ (\$input2 . \"\\\$\")) do={
:set output (\$x . \",\" . \$y) } } } }
:if ([:len \$output] = 0) do={ :set output \"-1,-1\" }
:set output [:toarray \$output]
};"
# -----------------
# End Functions
Code: Select all
# Script name: DemoFunctions
# Demo of function library
# Import Functions script and functions we are using
/system script run "Functions"
:global RandomNumGen
:global DateToNum
:global TimeToNum
# Demo: RandomNumGen
:global DemoRandomNum 0
:local runFunc [:parse (":global DemoRandomNum;" . \
$RandomNumGen . \
":set DemoRandomNum \$output")
]
$runFunc
:put ("Random number: " . [:pick $DemoRandomNum 0])
# Demo: DateToNum
:global DemoDate 0
:local runFunc [:parse (":global DemoDate;" . \
":local input [/system clock get date]; " . \
$DateToNum . \
":set DemoDate \$output")
]
$runFunc
:put ("Date to number: " . [:pick $DemoDate 0])
# Demo: TimeToNum
:global DemoTime 0
:local runFunc [:parse (":global DemoTime;" . \
":local input [/system clock get time]; " . \
$TimeToNum . \
":set DemoTime \$output")
]
$runFunc
:put ("Time to number: " . [:pick $DemoTime 0])