Use Functions in CMD Script

From MikroTik Wiki
Jump to: navigation, search

Functions in CMD Scripts

The below code will allow you to use functions in your RouterOS CMD scripts. I was finding myself using the same code snippet multiple times, in multiple scripts. This was not only inconsistent, but also time consuming, as I had to adapt the code each time it was inserted into a new script. If I wrote a routine that needed to be changed, I would have to change it (and remember where) in every script that used it.

By using functions, you're able write one piece of code and "call" that code from any other script. If you need to make a change to a it, you only need to do it once, at the function's source. Functions also provide consistency, as you're not copying and pasting each time you need to use the same piece of code.

Here is the main function library. You could also separate function libraries, say Functions-Text, Functions-Firewall, etc...

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

# UniqueNumGen: Generates a fairly unique number from date, time, mem-free, and cpu-load
# Input array: none
# Output array:
#   0 = number generated
:global UniqueNumGen ":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]
         };"

# -----------------
# End Functions

Here is a demo to show how functions can be used in your CMD scripts:

# Script name: DemoFunctions
# Demo of function library

# Import Functions script and functions we are using
/system script run "Functions"
:global UniqueNumGen
:global DateToNum
:global TimeToNum

# Demo: UniqueNumGen
:global DemoUniqueNum 0
:local runFunc    [:parse   (":global DemoUniqueNum;" . \
          $UniqueNumGen . \
          ":set DemoUniqueNum \$output")
      ]
$runFunc
:put ("Unique number: " . [:pick $DemoUniqueNum 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])

Feel free to contribute your functions here as well.

More Functions

Recursive function in CMD script: This function will list all possible three character combination of numbers 1, 2, and 3.

:local runFunc

:global output ""
:global recurseFunc (":global recurseFunc;
		      :global output;
		      :local runFunc;
		      :if ([:len \$base] < 3) do={
		         :foreach c in=[:toarray \"1,2,3\"] do={
		            :set output (\$output . \",\" . \$base . [:tostr \$c])
		            :set runFunc (\":local base \\\"\" . \$base . [:tostr \$c] . \"\\\"; \" . \$recurseFunc)
		            :set runFunc [:parse \$runFunc]
		            :put \$runFunc
		         }
		      }; ")

:set runFunc (":local base \"\"; " . $recurseFunc)
# To see how the function will be interperted, uncomment next line
#:put $runFunc
:set runFunc [:parse $runFunc]
:put $runFunc
:foreach char in=[:toarray $output] do={
   :put [:tostr $char]
}