other than to load them with a script every reboot, is there any way to get an environment variable to persist between multiple reboots?
No, this was discussed in the 7.1beta3 thread a few days ago.
by baidu translate :
I have a method to define a schedule to read environment variables to the array every minute. In the definition of the second boot from the start of the schedule. Use the acquired array to write to the second schedule at any time. Maybe the idea is to make it by yourself
There is only one command to demonstrate :
:put [/system script environment print as-value ]
OP did not want a script or using scheduling.
I agree that there should be a way to set persistent variables that survives reboot.
You can add a fw rule it stays trough a reboot, so should a persistent variable do as well.
For the moment you can kinda-sorta get away with it by storing variables as comments. The layer7-protocol area is not a bad one because it is practically unused these days so it doesn’t clutter up the interface if you put a bunch of variables in there
Comments will not store arrays correctly, or rather the ‘toarray’ command to convert a string back to an array doesn’t work because arrays store with semi-colon separates. Whereas the ‘toarray’ command uses commas to separate them (why mikrotik why?)
But this method works just fine for simpler things. I use it for incrementing a counter in a few scripts. One of them being a template that runs at a later time, where say a router is told to change some config and then reboot. Well the first command is to increment an integer in the comment of that scheduled task, it’s first read and if the counter is higher than say 1 then something has gone wrong, commands havn’t executed properly, script has failed, it failed to self-delete (otherwise its just going to reboot every single day at 3am forever) etc so it’ll then send an email to support desk as well as a remote syslog message to alert that somethings not right and requires manual intervention
search tag # rextended save and restore global variables on reboot
This is for save and restore variables with keeping the right data type on restore:
Scheduled script do that every x minutes, on purpose store only variables, but do not store codes or functions
because till now I do not have find one way to do that.
code = from “:parse” function, like :global c [:parse “/interface print”]
function = created like :global f do={ /interface print }, but is reported as array from :typeof
Only simple arrays are exported, do not work for array of array and more complex data structure.
/system script environment
:foreach item in=[find] do={
:local vname [get $item name]
:local vvalue [get $item value]
:if ($vvalue~"^\\*") do={:set vvalue "ID$vvalue"}
:if ($vvalue~"^(\\(code\\)|;\?\\(eva\?l )") do={:set vvalue "(code)"}
/ip firewall layer7
remove [find where name=$vname]
add name=$vname comment="$vvalue"
:delay 10ms
:execute "/ip firewall layer7 set [find where name=$vname] regexp=[:typeof \$$vname]"
:if ($vvalue="(code)") do={:delay 10ms ; set [find where name=$vname] regexp="code"}
}
Store variable name… on name, variable type on regexp, variable contents on comment.
On reboot this script is scheduled at startup, this restore also variables that do not contain readable data, like binary data, lower numbers and special characters:
/ip firewall layer7
:foreach item in=[find where regexp~"^(array|bool|code|id|ip|ip-prefix|ip6|ip6-prefix|lookup|nil|nothing|num|str|time)\$"] do={
:local vname [get $item name]
:local vvalue [get $item comment]
:local vtype [get $item regexp]
/system script environment
remove [find where name=$vname]
:if ($vtype~"^(array|ip|ip6|num|str|time)\$") do={
:execute ":global $vname [:to$vtype [/ip firewall layer7 get [find where name=$vname] comment]]"
} else={
:if ($vtype~"^(bool|id|ip-prefix|ip6-prefix|lookup|nil|nothing)\$") do={
:if ($vtype="bool") do={:execute ":global $vname [:tobool $vvalue]"}
:if ($vtype="id") do={:execute ":global $vname [:toid $[:pick $vvalue [:find $vvalue "*" -1] [:len $vvalue]]]"}
:if (($vtype="ip-prefix") or \
($vtype="ip6-prefix")) do={:execute ":global $vname [[:parse \":return $vvalue\"]]"}
:if ($vtype="lookup") do={:execute ":global $vname \"\$$vname\""}
:if ($vtype="nil") do={:execute ":global $vname"}
:if ($vtype="nothing") do={:execute ":global $vname [:nothing]"}
} else={
# vtype="code"
:log error "Unknow variable >$vname< of type >$vtype<"
:execute ":global $vname [/ip firewall layer7 get [find where name=$vname] comment]"
}
}
:delay 10ms
}
True Level 7 rules for Firewall are not “touched” unless they regexp is exactly a single word as the names of reserved variable types.
Someone know the full list of variable types???
standard:
array
bool
id
ip
ip6
num
str
time
broken, but restored with an hack:
ip-prefix
ip6-prefix
not recoverable:
code
function (reported as array)
“undefined” types:
nil
nothing
lookup ($0 on functions)
The script is not fixed for unknow data types discovered from me on 2023:
https://forum.mikrotik.com/viewtopic.php?p=1014223#p1014223
apireq (api request)
exclamation
cmd
iterator
backreference
EDIT: added fix for new discovered “op” on RouterOS, thanks to @tabraham report
2025 EDIT: added missing types discovered on 2023
Any word regarding persistent variables in v7 yet?
Sorry, but I think this is out of interest from MikroTik until the release of RouterOS 7.7.7 (stable)
Rumors say 7.9 that also will include the ability to catch well documented error numbers and messages.
updated for better support ID, code and function variables,
tested on both v6 and v7
Your script works very well friend REX, the only thing is that how could it be removed from the LOG so that it does not register every time the variables are saved in the LAYER 7
EL DONCITO.
you can’t without disabling all logs.
ok.
EL DONCITO.
Very useful this script, thanks!
BR.
Very thanks!
See also on my signature for other scripts
I do not have catalogued all script I have done… one day…
Thanks to the author for the very beautifully written scripts for saving and restoring global variables.
There are comments:
In the save script, you need to remove the save “(function)”, since it will not be possible to restore the function code.
Only variables should be saved and restored.
When restoring, restoring boolean variables via :execute does not work for me,
all boolean variables are restored as nil (have no values).
I had to insert such a check and restore via :parse
:if ($vtype = "bool") do={
[[:parse ":global $vname [:to$vtype $[/ip firewall layer7 get [find where name=$vname] regexp]]"]]}
In this form, everything works.
You also need to remove the line from the recovery script
:if ($vvalue = "(function)") do={:set vtype "function" }
since the functions are not saved and they do not need to be restored, they will have to be redefined again.
Yes, a bug, but simply solved with
:if ($vtype="bool") do={:execute ":global $vname [:tobool $vvalue]"}
Thanks for the info, I do some restyling and also fix boolean.
About “(function)” (and CODE!)
it was put there for some reasons:
- manage all the types as possible,
- in the future maybe they can be managed directly, and it is already ready
- is ready for add on script the search for file in (flash/)functions/vname.rsc or (flash/)codes/vname.rsc and load it at startup, if the file exist…
On this way also codes and functions are restored…
But is not intended to store inside the file the code “(eval /interface print)” because also if restored, can be restored only as string,
actually there is no way to convert directly “(eval /interface print)” to code or function.
It’s all clear. But, if you insert the saving of a function variable as, for example, (function), then during the subsequent restoration, the code of active functions in the environment will be corrupted and they will need to be redefined. If you do not save the functions, then you do not need to restore them, then the code of the active environment functions will be saved and they will be operational after restoring global variables of other types.
You forget something: is for restore variables on reboot, not at any arbitrary time…
On reboot no previous variables or functions or codes exists…
And see point 3) on previous post…
I have not forgotten, your script is also convenient for saving and restoring variables not only during reboot, but also at any time!