*** [Scripting examples - RouterOS - MikroTik Documentation](https://help.mikrotik.com/docs/spaces/ROS/pages/139067404/Scripting+examples) # MikroTik RouterOS Scripting – **Variables Cheat‑Sheet** > **Updated:** 7 Aug 2025 > Tested on *RouterOS v7.15* (the syntax remains backward‑compatible to ≥ v6.48 unless explicitly noted). --- ## Table of Contents 1. [Variable Declaration & Scope](#1-variable-declaration--scope) 2. [Data Types](#2-data-types) 3. [Inspecting Variables at Runtime](#3-inspecting-variables-at-runtime) 4. [Type Conversion & Casting](#4-type-conversion--casting) 5. [Working with *ip* & *ip‑prefix*](#5-working-with-ip--ip-prefix) 6. [Arrays, Dictionaries & Nested Structures](#6-arrays-dictionaries--nested-structures) 7. [Common Pitfalls & Debug Tips](#7-common-pitfalls--debug-tips) 8. [Mini‑Cookbook (ready‑to‑use snippets)](#8-mini-cookbook-ready-to-use-snippets) 9. [Quick Reference](#9-quick-reference) --- ## 1  Variable Declaration & Scope | Keyword | Visibility | Life‑time | Typical use | | --------- | ---------------------------------------------------------------------------------------------- | ------------------------------------------------------------------------ | ---------------------------------------------------------- | | `:global` | Global across **all** scripts executed by the same RouterOS user profile | Until it is explicitly unset with `:set myVar` or the router is rebooted | Inter‑script state, cached look‑ups, long‑running counters | | `:local` | Current scope **only** (the curly‑brace block, function, or interactive line that declared it) | Disappears as soon as execution leaves the block | Temporary loop counters, return values, throw‑away buffers | ```rsc :global buildDate "2025‑08‑07"; { :local tmp [/system resource get uptime]; :put "Uptime = $tmp"; } :put $tmp # -> *syntax error* (tmp is out of scope) ``` Each line you type in the interactive terminal acts as its own **implicit local scope**, so local variables are *not* visible to the next line ([help.mikrotik.com](https://help.mikrotik.com/docs/spaces/ROS/pages/47579229/Scripting)). > **Tip:** If you need to read a global from inside a function, *re‑declare* it inside the function: > > ```rsc > :global token "XYZ123" > :global showToken do={ > :global token; > :return $token; > } > ``` --- ## 2  Data Types RouterOS recognises the following primitive data types: ([help.mikrotik.com](https://help.mikrotik.com/docs/spaces/ROS/pages/47579229/Scripting)) | Type | Notes | | -------------------- | --------------------------------------------------------------- | | `num` | 64‑bit signed integer (hex input with `0x` allowed) | | `bool` | `true` or `false` | | `str` | UTF‑8 string | | `ip` | IPv4 address (`10.0.0.1`) | | `ip‑prefix` | IPv4 prefix (`10.0.0.0/24`) | | `ip6` / `ip6‑prefix` | IPv6 address or prefix | | `id` | Internal hex ID (always starts with `*`) | | `time` | Absolute date‑time or time interval | | `array` | Ordered list or key/value dictionary | | `nil` | Unassigned / *nothing* (default when you declare without value) | --- ## 3  Inspecting Variables at Runtime | Task | Command | | ---------------- | ----------------------------------------------------- | | Show **value** | `:put $myVar` | | Show **type** | `:put [:typeof $myVar]` | | List all globals | `/system script environment print` | | Filter by name | `/system script environment print where name="myVar"` | Example session: ```rsc :global newPrefix 192.0.2.0/24 :put [:typeof $newPrefix] # -> ip‑prefix :put $newPrefix # -> 192.0.2.0/24 ``` --- ## 4  Type Conversion & Casting Conversions are explicit; the shell will **not** silently cast between unrelated types (e.g. *str* ↔︎ *ip‑prefix*). Common helpers: | Function | Converts … | | ------------------- | -------------------- | | `:tostr VALUE` | → `str` | | `:tonum VALUE` | → `num` | | `:toip VALUE` | → `ip` / `ip‑prefix` | | `:toarray VALUE` | → `array` | | `:tonothing` / `""` | → `nil` | ```rsc # Compare an address coming from CLI (string) with one stored as ip‑prefix :local needle 111.111.1.1/24 /ip address print where address=[:tostr $needle] ;# OK ``` Trying to compare `str` with `ip‑prefix` directly fails for the same reason (`find` returns nothing) ([help.mikrotik.com](https://help.mikrotik.com/docs/spaces/ROS/pages/283574370/Scripting%2BTips%2Band%2BTricks)). --- ## 5  Working with `ip` & `ip‑prefix` These types unlock bitwise operators, prefix‑matching, and membership tests: ```rsc :put (192.168.88.77 & 255.255.255.0) # subnet address :put (192.168.1.5 in 192.168.0.0/16) # true ``` ### Calculating broadcast ```rsc :local net 192.168.88.0 :local mask 255.255.255.0 :local bcast ($net | (~$mask)) :put $bcast # -> 192.168.88.255 ``` ### Avoiding string traps Store prefixes as `ip‑prefix`, **not** `str`, whenever you intend to use routing / filter expressions. Casting back to string is cheap: `:tostr $prefix`. --- ## 6  Arrays, Dictionaries & Nested Structures Create: ```rsc :global emptyArr [:toarray ""] :global dict {user="admin"; pass="secret"} ``` Access / mutate: ```rsc :put ($dict->"user") # admin :set ($dict->"pass") "p@ss!" :set ($emptyArr->0) "first" ``` Multi‑dimensional arrays work the same: ```rsc :global matrix {{"11";"12"};{"21";"22"}} :set ($matrix->1->0) "20" ``` See more idioms on the official “Tips & Tricks” page ([help.mikrotik.com](https://help.mikrotik.com/docs/spaces/ROS/pages/283574370/Scripting%2BTips%2Band%2BTricks)). --- ## 7  Common Pitfalls & Debug Tips | Gotcha | Fix | | ----------------------------------------------------------- | ---------------------------------------------------------------------------------------------------------------------------------------------------------- | | **Using console numbers** (`set 0 name=LAN`) inside scripts | Use `.id` or `find`, never buffer indexes ([help.mikrotik.com](https://help.mikrotik.com/docs/spaces/ROS/pages/283574370/Scripting%2BTips%2Band%2BTricks)) | | Comparing mismatched types (`str` vs `ip‑prefix`) | Cast with `:tostr` / `:toip` | | Shadowing globals inside functions | Re‑declare with `:global myVar;` inside the function | | Forgetting to unset unused globals | `:set myVar` (no value) to remove it ([help.mikrotik.com](https://help.mikrotik.com/docs/spaces/ROS/pages/283574370/Scripting%2BTips%2Band%2BTricks)) | | Non‑unique variable names (clashing with built‑ins) | Prefix your vars (e.g. `my_`, `ctx_`) | --- ## 8  Mini‑Cookbook (ready‑to‑use snippets) ### 8.1  Detect & log WAN IP changes ````rsc :global currentIP :local newIP [/ip address get [find interface="ether1"] address] :if ($newIP != $currentIP) do={ :log info "IP changed $currentIP → $newIP" :set currentIP $newIP } ``` ([help.mikrotik.com](https://help.mikrotik.com/docs/spaces/ROS/pages/139067404/Scripting%2Bexamples)) ### 8.2  Strip CIDR mask ```rsc :local ipWithMask 10.1.101.1/24 :put [:pick $ipWithMask 0 [:find $ipWithMask "/"]] ```` ### 8.3  Define an empty array ```rsc :global myArr [:toarray ""] ``` --- ## 9  Quick Reference | Action | One‑liner | | -------------- | ---------------------- | | Declare global | `:global gVar [value]` | | Declare local | `:local lVar [value]` | | Change value | `:set gVar newValue` | | Unset variable | `:set gVar` | | Print value | `:put $gVar` | | Print type | `:put [:typeof $gVar]` | | Cast to string | `:tostr $gVar` | | Create prefix | `:toip 192.0.2.0/24` | ---