I want to write an export script to reuse the exported settings with other hardware. Because of hardware specific things like MAC-Address I want to filter such things like the MAC.
First step I need is the text of the export command is saved to a variable. But how?
The following simple code doesn’t work.
:local Text
:set Text ([/interface wireless sniffer export])
The variable Text is empty.
How to save this export text in the variable Text?
Not directly related to the question, but if you’re going to create a full configuration export as a final goal, that’s likely going to be larger than 4096 bytes, which is the size limit for RouterOS variables.
You can’t store the direct export as a variable, but…
you can obtain the same output using print as-value.
The below code will output wireless interface settings to file(s). Each file can be independently run using ‘/import’. Also, if a file would exceed 4096 bytes, it increments to the next file (wireless-interface1, wireless-interface2, etc…)
# Do not include '.rsc', it is appended automatically
:local filename "wireless-interface"
# Internal processing below...
# ----------------------------------
:local line
:local contents
:local fileindex 1
:local findindex
:local property
:local value
/interface wireless {
:set contents "/interface wireless\n"
# loop through wireless interfaces, getting their advanced (plus basic) settings
:foreach r in=[print advanced as-value] do={
:set line ""
:foreach i in=[:toarray $r] do={
:set findindex [:find [:tostr $i] "="]
:set property [:pick [:tostr $i] 0 $findindex]
:set value [:pick [:tostr $i] ($findindex + 1) [:len [:tostr $i]]]
# do not include '.id' property, it will be different on other routers
# do not include interface-'type' property, it is read-only
:if ([:tostr $property] = ".id" || \
[:tostr $property] = "interface-type") do={
:set property ""
:set value ""
}
# put quotes around comment property
# put quotes around value if it contains spaces
:if ([:tostr $property] = "comment" || \
[:len [:find [:tostr $value] " "]] > 0) do={
:set value ("\"" . $value . "\"")
}
# append property=value to line
:if ([:len $property] > 0 && [:len $value] > 0) do={
# use [find] with mac-address (easier import to other routers)
:if ([:tostr $property] = "mac-address") do={
:set line ("[find mac-address=\"" . $value . "\"]" . " " . [:tostr $line])
} else={
:set line ([:tostr $line] . $property . "=" . $value . " ")
}
}
# end foreach i
}
:set line ("set " . [:tostr $line] . "\n")
# if contents + line is over filesize limit, write out to file
:if (([:len [:tostr $contents]] + [:len [:tostr $line]]) > 4096) do={
/system identity export file=($filename . $fileindex)
# wait for file to appear (this is needed)
:while ([:len [/file find name=($filename . $fileindex . ".rsc")]] = 0) do={}
/file set ($filename . $fileindex . ".rsc") contents=[:tostr $contents]
:set contents "/interface wireless\n"
:set fileindex ($fileindex + 1)
}
# append line to contents
:set contents ([:tostr $contents] . [:tostr $line])
}
# write remaining contents
:if ([:len $contents] > 0) do={
/system identity export file=($filename . $fileindex)
# wait for file to appear (this is needed)
:while ([:len [/file find name=($filename . $fileindex . ".rsc")]] = 0) do={}
/file set ($filename . $fileindex . ".rsc") contents=[:tostr $contents]
}
# /interface wireless
}
I know this may look complex, but it shouldn’t be too hard once you dig into it. Also, this script could be adapted for any settings within RouterOS that you want to output to a file, making a custom script from RouterOS’s settings.
Hope this helps. If you have any problems, or suggestions on how to improve it, let me know.
What is the allowed length of a comment field (in bytes)? Maybe I should check for variable length would exceed 4096, then dynamically allocate the next available variable (var1, var2, var3, etc…, just like I have with files?
Unfortunately, the RouterOS scripting language and limited (no shell/bash) means a lot of work has to be done for simple tasks, like export a custom config, or import a plain text file of IP addresses that exceed 4096 bytes, which is a very small amount.
What would you suggest I change on the above script to make it fail-safe?
correction. that 4KB limitation is there if you want to save and read from file, if you want to set or read variables and it is not connected with files, only router memory is your limiting factor. (as it seems now - long, from C)
Is this true for all versions of RouterOS (a variable can be larger then 4096 bytes if not read from file), or is this only in a new/specific version(s)?
I was always under the assumption that all variables (being read from file & set in terminal & set in script) had a limitation of 4096 bytes?
Also, is there a way of testing the memory before setting / appending a variable? For example, if I have a very large filter address-list, and I want to set it’s contents to a variable, how would I check that I have enough memory to store this contents?
always variables could hold more data than 4KB. Only limitation is how much you can write/read to file.
you can assign very very large amounts of memory. More free memory you have higher you can go. That is, if you increase the variable you have to be aware of memory allocation mechanisms. If you just using large value, you do not have to worry about that at all.