Syntax

RouterOS script language is a powerful scripting environment designed specifically for network device automation. Understanding the syntax is essential for creating effective automation scripts.

This comprehensive syntax reference covers all aspects of RouterOS scripting language, from basic variables to advanced control structures.


Script structure and basics

Script execution context

# Scripts can be executed in multiple ways:

# 1. Direct execution in terminal
{
    /log info "Direct execution";
    :local message "Hello World";
    /log info $message;
}

# 2. Stored script execution
/system script add name=my-script source={
    /log info "Stored script execution";
}
/system script run my-script

# 3. Scheduler execution
/system scheduler add name=scheduled-task interval=1h on-event={
    /log info "Scheduled execution";
}

# 4. Event-triggered execution (inline)
/ip firewall filter add chain=input action=log log-prefix="BLOCKED" \
    src-address-list=blocked-ips

Comments and documentation

# Single-line comment - starts with hash symbol

# Multi-line documentation
# This script performs system monitoring
# Author: Network Administrator
# Version: 1.0
# Last modified: 2024-11-30

{
    # Inline comments within code blocks
    :local systemName [/system identity get name];  # Get router identity
    
    # Comments can appear anywhere on a line after code
    /log info $systemName;  # Log the system name
    
    # Block comments for complex explanations
    # The following section handles error conditions
    # It implements a retry mechanism with exponential backoff
    # Maximum retry attempts: 3
    :local retryCount 0;
}

Variables and data types

Variable declaration and naming

# Variable naming rules and examples
{
    # Valid variable names
    :local validName "correct";
    :local userName "john_doe";
    :local counter1 42;
    :local isActive true;
    :local _privateVar "underscore prefix";
    :local CamelCase "mixed case";
    
    # Global variables
    :global globalCounter 0;
    :global systemConfig "production";
    
    # Invalid names (commented out to prevent errors)
    # :local 123invalid "cannot start with number";
    # :local my-variable "hyphens not allowed";
    # :local class "class is reserved word";
    # :local if "if is reserved word";
}

Data type examples

# Comprehensive data type examples
{
    # String data type
    :local stringVar "Hello World";
    :local emptyString "";
    :local stringWithQuotes "He said \"Hello\"";
    :local multiLineString "Line 1\nLine 2\nLine 3";
    :local pathString "/system/identity";
    
    # Numeric data type
    :local integerVar 42;
    :local negativeNum -15;
    :local largeNumber 1000000;
    :local hexNumber 0xFF;    # Hexadecimal
    :local octalNumber 0777;  # Octal
    
    # Boolean data type
    :local boolTrue true;
    :local boolFalse false;
    :local yesValue yes;      # Equivalent to true
    :local noValue no;        # Equivalent to false
    
    # IP address data type
    :local ipv4Address 192.168.1.1;
    :local ipv6Address 2001:db8::1;
    :local ipWithMask 192.168.1.0/24;
    :local ipRange 192.168.1.10-192.168.1.20;
    
    # Time data type
    :local timeValue 1d2h3m4s;
    :local seconds 30s;
    :local minutes 15m;
    :local hours 2h;
    :local days 7d;
    :local weeks 2w;
    
    # Array data type
    :local simpleArray {1; 2; 3; 4; 5};
    :local mixedArray {42; "text"; true; 192.168.1.1};
    :local emptyArray {};
    :local stringArray {"apple"; "banana"; "cherry"};
    
    # Associative array (dictionary-like)
    :local configDict {
        hostname="router1";
        ip=192.168.1.1;
        enabled=true;
        vlan=100
    };
    
    # Nested arrays
    :local nestedArray {
        {name="user1"; role="admin"};
        {name="user2"; role="user"};
        {name="user3"; role="guest"}
    };
    
    # Nothing type (null/undefined equivalent)
    :local undefinedVar;  # Type is "nothing"
    :local nullValue [:nothing];
}

Operators and expressions

Arithmetic operators

# Mathematical operations
{
    :local a 10;
    :local b 3;
    
    # Basic arithmetic
    :local sum ($a + $b);           # Addition: 13
    :local difference ($a - $b);    # Subtraction: 7  
    :local product ($a * $b);       # Multiplication: 30
    :local quotient ($a / $b);      # Division: 3 (integer division)
    :local remainder ($a % $b);     # Modulo: 1
    
    # Order of operations (PEMDAS/BODMAS)
    :local complex (($a + $b) * 2 - $a / 2);  # Result: 21
    :local withParens ((($a + $b) * 2) - ($a / 2));  # Explicit grouping
    
    # Working with negative numbers
    :local negative (-$a);          # Unary minus: -10
    :local subtractNegative ($a - (-$b));  # Double negative: 13
    
    /log info ("Sum: " . $sum . ", Product: " . $product);
}

Comparison operators

# Comparison operations
{
    :local x 10;
    :local y 20;
    :local str1 "apple";
    :local str2 "banana";
    
    # Numeric comparisons
    :local isEqual ($x = $y);         # false (equality)
    :local notEqual ($x != $y);       # true (inequality)  
    :local lessThan ($x < $y);        # true
    :local lessEqual ($x <= $y);      # true
    :local greaterThan ($x > $y);     # false
    :local greaterEqual ($x >= $y);   # false
    
    # String comparisons
    :local strEqual ($str1 = $str2);     # false
    :local strNotEqual ($str1 != $str2); # true
    :local strLess ($str1 < $str2);      # true (alphabetical order)
    
    # Pattern matching with ~ operator
    :local matchResult ($str1 ~ "app.*");     # true (regex-like matching)
    :local noMatch ($str1 ~ "ban.*");         # false
    
    # IP address comparisons
    :local ip1 192.168.1.1;
    :local ip2 192.168.1.100;
    :local network 192.168.1.0/24;
    
    :local ipEqual ($ip1 = ip2);              # false
    :local inNetwork ($ip1 in $network);      # true (IP in subnet)
    
    /log info ("x < y: " . $lessThan . ", str1 < str2: " . $strLess);
}

Logical operators

# Boolean logic operations
{
    :local a true;
    :local b false;
    :local c true;
    
    # Basic logical operators
    :local andResult ($a && $b);      # false (logical AND)
    :local orResult ($a || $b);       # true (logical OR)
    :local notResult (!$a);           # false (logical NOT)
    
    # Complex logical expressions
    :local complexAnd ($a && $b && $c);       # false
    :local complexOr ($a || $b || $c);        # true
    :local mixedLogic (($a && $c) || $b);     # true
    :local deMorgan (!($a && $b));            # true (!false = true)
    
    # Short-circuit evaluation
    :local shortCircuit ($b && $a);   # false (b is false, so $a not evaluated)
    
    # Combining with comparisons
    :local num 15;
    :local inRange ($num > 10 && $num < 20);  # true
    :local outOfRange ($num < 5 || $num > 25); # false
    
    /log info ("AND result: " . $andResult . ", OR result: " . $orResult);
}

String operators

# String manipulation and operations
{
    :local firstName "John";
    :local lastName "Doe";
    :local separator " ";
    
    # String concatenation with . operator
    :local fullName ($firstName . $separator . $lastName);  # "John Doe"
    :local greeting ("Hello, " . $fullName . "!");         # "Hello, John Doe!"
    
    # Multiple concatenations
    :local address ($firstName . " " . $lastName . " lives in " . "New York");
    
    # Concatenating different types (automatic conversion)
    :local age 25;
    :local description ($firstName . " is " . $age . " years old");
    
    # Empty string handling
    :local empty "";
    :local notEmpty ("Value: " . $empty . "END");  # "Value: END"
    
    # Special characters in strings
    :local withQuotes ("He said \"Hello\"");
    :local withNewlines ("Line 1\nLine 2\nLine 3");
    :local withTabs ("Column1\tColumn2\tColumn3");
    
    # String comparison with concatenation
    :local prefix "Hello";
    :local suffix "World";
    :local combined ($prefix . " " . $suffix);
    :local matches ($combined = "Hello World");  # true
    
    /log info ("Full name: " . $fullName);
    /log info ("Description: " . $description);
}

Control structures

Conditional statements

# Comprehensive if-else examples
{
    :local temperature 25;
    :local humidity 60;
    :local userRole "admin";
    
    # Basic if statement
    :if ($temperature > 30) do={
        /log warning "High temperature detected";
    };
    
    # If-else statement
    :if ($temperature > 30) do={
        /log warning "Temperature too high";
    } else={
        /log info "Temperature normal";
    };
    
    # Nested if-else (else-if simulation)
    :if ($temperature > 35) do={
        /log error "Critical temperature";
    } else={
        :if ($temperature > 30) do={
            /log warning "High temperature";
        } else={
            :if ($temperature < 10) do={
                /log warning "Low temperature";
            } else={
                /log info "Normal temperature";
            };
        };
    };
    
    # Multiple conditions with logical operators
    :if ($temperature > 25 && $humidity > 70) do={
        /log info "Hot and humid conditions";
    } else={
        :if ($temperature > 25 || $humidity > 70) do={
            /log info "Either hot or humid";
        } else={
            /log info "Comfortable conditions";
        };
    };
    
    # String-based conditions
    :if ($userRole = "admin") do={
        /log info "Administrator access granted";
    } else={
        :if ($userRole = "user") do={
            /log info "User access granted";
        } else={
            :if ($userRole = "guest") do={
                /log info "Guest access granted";
            } else={
                /log error "Unknown user role";
            };
        };
    };
    
    # Complex conditional with multiple variables
    :local systemLoad 75;
    :local memoryUsage 80;
    :local diskSpace 90;
    
    :if ($systemLoad > 80 && $memoryUsage > 85 && $diskSpace > 95) do={
        /log error "System critical - all resources high";
    } else={
        :if ($systemLoad > 70 || $memoryUsage > 75 || $diskSpace > 85) do={
            /log warning "System under stress";
        } else={
            /log info "System resources normal";
        };
    };
}

Loop structures

# Various loop implementations
{
    # Basic foreach with array
    :local numbers {1; 2; 3; 4; 5};
    :foreach number in=$numbers do={
        :local squared ($number * $number);
        /log info ("Number: " . $number . ", Squared: " . $squared);
    };
    
    # Foreach with string array
    :local fruits {"apple"; "banana"; "cherry"; "date"};
    :foreach fruit in=$fruits do={
        :local message ("Processing fruit: " . $fruit);
        /log info $message;
    };
    
    # Foreach with command results
    :foreach interface in=[/interface print as-value] do={
        :local ifName ($interface->"name");
        :local ifType ($interface->"type");
        :local isRunning ($interface->"running");
        
        :if ($isRunning) do={
            /log info ("Interface " . $ifName . " (" . $ifType . ") is UP");
        } else={
            /log warning ("Interface " . $ifName . " (" . $ifType . ") is DOWN");
        };
    };
    
    # Nested foreach loops
    :local departments {"IT"; "Sales"; "Marketing"};
    :local priorities {"High"; "Medium"; "Low"};
    
    :foreach dept in=$departments do={
        :foreach priority in=$priorities do={
            :local task ($dept . " - " . $priority . " Priority");
            /log info ("Task: " . $task);
        };
    };
    
    # While loop simulation using recursion and counters
    :local counter 0;
    :local maxCount 5;
    
    # While loop equivalent
    :while ($counter < $maxCount) do={
        /log info ("Counter value: " . $counter);
        :set counter ($counter + 1);
        
        # Break condition simulation
        :if ($counter >= 3) do={
            /log info "Breaking early at counter 3";
            :set counter $maxCount;  # Force exit
        };
    };
    
    # For loop simulation with range
    :for i from=1 to=10 step=2 do={
        :local message ("Odd number: " . $i);
        /log info $message;
    };
    
    # Countdown loop
    :for i from=10 to=1 step=-1 do={
        /log info ("Countdown: " . $i);
        :if ($i = 1) do={
            /log info "Blast off!";
        };
    };
}

Functions and procedures

Built-in function usage

# Comprehensive built-in function examples
{
    # String manipulation functions
    :local originalText "Hello World RouterOS";
    
    # Length function
    :local textLength [:len $originalText];         # 19
    /log info ("Text length: " . $textLength);
    
    # Substring extraction with :pick
    :local greeting [:pick $originalText 0 5];      # "Hello"
    :local world [:pick $originalText 6 11];        # "World"
    :local routeros [:pick $originalText 12 20];    # "RouterOS"
    
    # Find substring position
    :local worldPos [:find $originalText "World"];   # 6
    :local osPos [:find $originalText "OS"];         # 17
    :local notFound [:find $originalText "Linux"];   # Returns nothing/empty
    
    # String replacement
    :local replaced [:replace $originalText "World" "Universe"];
    /log info ("Replaced: " . $replaced);  # "Hello Universe RouterOS"
    
    # Type conversion functions
    :local numberString "42";
    :local stringNumber [:tonum $numberString];      # 42 (number)
    :local backToString [:tostr $stringNumber];      # "42" (string)
    
    # IP address conversion
    :local ipString "192.168.1.1";
    :local ipAddress [:toip $ipString];              # IP type
    :local ipBack [:tostr $ipAddress];               # "192.168.1.1"
    
    # Time conversion
    :local timeString "1d2h3m4s";
    :local timeValue [:totime $timeString];          # Time type
    :local timeBack [:tostr $timeValue];             # "1d2h3m4s"
    
    # Array functions
    :local testArray {"one"; "two"; "three"; "four"; "five"};
    :local arrayLen [:len $testArray];               # 5
    :local firstTwo [:pick $testArray 0 2];         # {"one"; "two"}
    :local lastTwo [:pick $testArray 3 5];          # {"four"; "five"}
    
    # Mathematical functions (if available)
    :local angle 45;
    :local result [:sin $angle];                     # Sine of 45
    :local logResult [:log 100];                     # Logarithm of 100
    
    /log info ("Original: " . $originalText);
    /log info ("Greeting: " . $greeting . ", World at position: " . $worldPos);
}

Custom function definition

# Custom function examples and patterns
{
    # Simple function with single parameter
    :local greetUser do={
        :local userName $1;
        :local greeting ("Hello, " . $userName . "!");
        :return $greeting;
    };
    
    # Usage of simple function
    :local message [$greetUser "Alice"];
    /log info $message;  # "Hello, Alice!"
    
    # Function with multiple parameters
    :local calculateArea do={
        :local width $1;
        :local height $2;
        :local area ($width * $height);
        :return $area;
    };
    
    # Usage with multiple parameters
    :local roomArea [$calculateArea 10 12];
    /log info ("Room area: " . $roomArea . " square meters");
    
    # Function with parameter validation
    :local safeDivision do={
        :local numerator $1;
        :local denominator $2;
        
        # Input validation
        :if ($denominator = 0) do={
            /log error "Division by zero attempted";
            :return "ERROR";
        };
        
        :local result ($numerator / $denominator);
        :return $result;
    };
    
    # Test the safe division function
    :local validResult [$safeDivision 10 2];        # 5
    :local errorResult [$safeDivision 10 0];        # "ERROR"
    
    # Complex function with multiple return values (using array)
    :local analyzeSystem do={
        :local sysInfo [/system resource get];
        :local cpu ($sysInfo->"cpu-load");
        :local memory ($sysInfo->"free-memory");
        :local uptime ($sysInfo->"uptime");
        
        # Return multiple values as array
        :local results {
            cpu=$cpu;
            memory=$memory;
            uptime=$uptime;
            status="normal"
        };
        
        # Determine status based on values
        :if ($cpu > 80) do={
            :set ($results->"status") "high-cpu";
        };
        
        :return $results;
    };
    
    # Use complex function
    :local systemStatus [$analyzeSystem];
    /log info ("System status: " . ($systemStatus->"status"));
    /log info ("CPU load: " . ($systemStatus->"cpu") . "%");
    
    # Recursive function example
    :local factorial do={
        :local n $1;
        
        # Base case
        :if ($n <= 1) do={
            :return 1;
        };
        
        # Recursive case
        :local previousResult [$factorial ($n - 1)];
        :local result ($n * $previousResult);
        :return $result;
    };
    
    # Test recursive function
    :local fact5 [$factorial 5];  # 120
    /log info ("5! = " . $fact5);
    
    # Function with local variables and complex logic
    :local formatFileSize do={
        :local sizeInBytes $1;
        :local units {"B"; "KB"; "MB"; "GB"; "TB"};
        :local unitIndex 0;
        :local size $sizeInBytes;
        
        # Convert to appropriate unit
        :while ($size >= 1024 && $unitIndex < ([:len $units] - 1)) do={
            :set size ($size / 1024);
            :set unitIndex ($unitIndex + 1);
        };
        
        :local unit [:pick $units $unitIndex];
        :local formatted ($size . " " . $unit);
        :return $formatted;
    };
    
    # Test file size formatting
    :local largeFile [$formatFileSize 1073741824];  # "1 GB"
    /log info ("File size: " . $largeFile);
}

Array and data structure manipulation

Array operations

# Comprehensive array manipulation
{
    # Array creation and initialization
    :local emptyArray {};
    :local numberArray {1; 2; 3; 4; 5};
    :local stringArray {"red"; "green"; "blue"};
    :local mixedArray {42; "text"; true; 192.168.1.1};
    
    # Array access and modification
    :local firstNumber [:pick $numberArray 0];       # 1
    :local lastNumber [:pick $numberArray 4];        # 5
    :local middleNumbers [:pick $numberArray 1 4];   # {2; 3; 4}
    
    # Array length
    :local arrayLength [:len $numberArray];          # 5
    /log info ("Array has " . $arrayLength . " elements");
    
    # Array concatenation (simulated)
    :local array1 {1; 2; 3};
    :local array2 {4; 5; 6};
    :local combined {};
    
    # Combine arrays using foreach
    :foreach item in=$array1 do={
        :set combined ($combined, $item);
    };
    :foreach item in=$array2 do={
        :set combined ($combined, $item);
    };
    
    # Array searching
    :local searchArray {"apple"; "banana"; "cherry"; "date"};
    :local found false;
    :local searchTerm "cherry";
    
    :foreach item in=$searchArray do={
        :if ($item = $searchTerm) do={
            :set found true;
            /log info ("Found " . $searchTerm . " in array");
        };
    };
    
    # Array filtering (create new array with matching elements)
    :local numbers {1; 2; 3; 4; 5; 6; 7; 8; 9; 10};
    :local evenNumbers {};
    
    :foreach number in=$numbers do={
        :if (($number % 2) = 0) do={
            :set evenNumbers ($evenNumbers, $number);
        };
    };
    
    /log info ("Even numbers: " . [:tostr $evenNumbers]);
    
    # Multi-dimensional arrays
    :local matrix {
        {1; 2; 3};
        {4; 5; 6};
        {7; 8; 9}
    };
    
    # Access multi-dimensional array elements
    :local firstRow [:pick $matrix 0];               # {1; 2; 3}
    :local middleElement [:pick [:pick $matrix 1] 1]; # 5
    
    # Array of objects (associative arrays)
    :local users {
        {name="John"; age=30; role="admin"};
        {name="Jane"; age=25; role="user"};
        {name="Bob"; age=35; role="guest"}
    };
    
    # Process array of objects
    :foreach user in=$users do={
        :local userName ($user->"name");
        :local userAge ($user->"age");
        :local userRole ($user->"role");
        /log info ("User: " . $userName . ", Age: " . $userAge . ", Role: " . $userRole);
    };
}

Associative arrays (dictionaries)

# Dictionary/associative array operations
{
    # Create associative array (dictionary)
    :local config {
        hostname="router1";
        ip="192.168.1.1";
        mask=24;
        gateway="192.168.1.254";
        dns1="8.8.8.8";
        dns2="8.8.4.4";
        enabled=true;
        vlan=100
    };
    
    # Access dictionary values
    :local routerName ($config->"hostname");
    :local ipAddress ($config->"ip");
    :local isEnabled ($config->"enabled");
    
    /log info ("Router: " . $routerName . " at " . $ipAddress);
    
    # Modify dictionary values
    :set ($config->"hostname") "new-router";
    :set ($config->"enabled") false;
    
    # Add new key-value pairs
    :set ($config->"location") "DataCenter1";
    :set ($config->"contact") "admin@company.com";
    
    # Check if key exists (indirect method)
    :local keyExists false;
    :do {
        :local testValue ($config->"nonexistent");
        :set keyExists true;
    } on-error={
        :set keyExists false;
    };
    
    # Iterate through dictionary
    :foreach key,value in=$config do={
        /log info ("Key: " . $key . ", Value: " . [:tostr $value]);
    };
    
    # Nested dictionaries
    :local networkConfig {
        lan={
            interface="bridge1";
            ip="192.168.1.1/24";
            dhcp=true
        };
        wan={
            interface="ether1";
            type="dhcp-client";
            backup="ether2"
        };
        wifi={
            ssid="MyNetwork";
            password="SecurePass123";
            channel=36;
            enabled=true
        }
    };
    
    # Access nested dictionary values
    :local wifiSSID (($networkConfig->"wifi")->"ssid");
    :local lanInterface (($networkConfig->"lan")->"interface");
    :local wanType (($networkConfig->"wan")->"type");
    
    /log info ("WiFi SSID: " . $wifiSSID);
    /log info ("LAN Interface: " . $lanInterface);
    /log info ("WAN Type: " . $wanType);
    
    # Complex data structure example
    :local inventory {
        switches={
            count=5;
            models={"CRS328"; "CRS326"; "CRS312"};
            locations={"Floor1"; "Floor2"; "DataCenter"}
        };
        routers={
            count=3;
            models={"hAP ax3"; "CCR2004"; "RB5009"};
            firmware="7.16.1"
        };
        accessories={
            cables=50;
            adapters=20;
            licenses=10
        }
    };
    
    # Process complex data structure
    :local switchCount (($inventory->"switches")->"count");
    :local routerModels (($inventory->"routers")->"models");
    :local cableCount (($inventory->"accessories")->"cables");
    
    /log info ("Total switches: " . $switchCount);
    /log info ("Available cables: " . $cableCount);
    
    # Iterate through router models
    :foreach model in=$routerModels do={
        /log info ("Router model in inventory: " . $model);
    };
}

Error handling and flow control

Exception handling

# Comprehensive error handling examples
{
    # Basic try-catch equivalent
    :do {
        # Potentially risky operation
        /interface disable ether999;  # Interface might not exist
        /log info "Interface disabled successfully";
    } on-error={
        /log error "Failed to disable interface - interface may not exist";
    };
    
    # Error handling with error message capture (simulated)
    :local operationSuccess false;
    :local errorMessage "";
    
    :do {
        # Another risky operation
        /ip address add address=192.168.1.1/24 interface=ether1;
        :set operationSuccess true;
    } on-error={
        :set operationSuccess false;
        :set errorMessage "Failed to add IP address";
    };
    
    # React based on operation result
    :if ($operationSuccess) do={
        /log info "IP address configured successfully";
    } else={
        /log error $errorMessage;
        # Implement fallback procedure
        /log info "Trying alternative configuration...";
    };
    
    # Nested error handling
    :do {
        # Outer operation
        /log info "Starting complex operation";
        
        :do {
            # Inner operation that might fail
            /system reboot;
        } on-error={
            /log warning "Reboot failed, trying shutdown";
            
            :do {
                /system shutdown;
            } on-error={
                /log error "System shutdown also failed";
            };
        };
        
    } on-error={
        /log error "Entire operation sequence failed";
    };
    
    # Error handling with retry logic
    :local maxRetries 3;
    :local retryCount 0;
    :local success false;
    
    :while ($retryCount < $maxRetries && !$success) do={
        :do {
            # Operation that might fail
            /tool fetch url="http://example.com/test" dst-path="test.txt";
            :set success true;
            /log info "Download completed successfully";
        } on-error={
            :set retryCount ($retryCount + 1);
            /log warning ("Download failed, attempt " . $retryCount . " of " . $maxRetries);
            
            :if ($retryCount < $maxRetries) do={
                /log info "Retrying in 5 seconds...";
                :delay 5s;
            } else={
                /log error "All retry attempts failed";
            };
        };
    };
    
    # Error handling with different error types (simulated)
    :local handleNetworkOperation do={
        :local operation $1;
        :local target $2;
        
        :if ($operation = "ping") do={
            :do {
                /tool ping address=$target count=3;
                /log info ("Ping to " . $target . " successful");
            } on-error={
                /log warning ("Ping to " . $target . " failed - host unreachable");
            };
        } else={
            :if ($operation = "fetch") do={
                :do {
                    /tool fetch url=$target;
                    /log info ("Fetch from " . $target . " successful");
                } on-error={
                    /log warning ("Fetch from " . $target . " failed - connection error");
                };
            } else={
                /log error ("Unknown operation: " . $operation);
            };
        };
    };
    
    # Use the error handling function
    [$handleNetworkOperation "ping" "8.8.8.8"];
    [$handleNetworkOperation "fetch" "http://example.com"];
    [$handleNetworkOperation "invalid" "target"];
}

Advanced syntax features

Pattern matching and regular expressions

# Pattern matching and text processing
{
    # Basic pattern matching with ~ operator
    :local text "Hello World RouterOS";
    :local hasHello ($text ~ "Hello");           # true
    :local hasRouter ($text ~ "Router");         # true  
    :local hasLinux ($text ~ "Linux");           # false
    
    # Case-insensitive matching (RouterOS specific)
    :local textLower "hello world routeros";
    :local matchCase ($textLower ~ "Hello");     # false (case sensitive)
    
    # Wildcard patterns (simplified regex-like)
    :local filename "config.backup.rsc";
    :local isBackup ($filename ~ ".*backup.*");  # true
    :local isConfig ($filename ~ "config.*");    # true
    :local isScript ($filename ~ ".*\\.rsc");    # true
    
    # IP address pattern matching
    :local ipAddr "192.168.1.100";
    :local isPrivateA ($ipAddr ~ "^10\\..*");           # false
    :local isPrivateB ($ipAddr ~ "^172\\.(1[6-9]|2[0-9]|3[0-1])\\..*"); # false
    :local isPrivateC ($ipAddr ~ "^192\\.168\\..*");    # true
    
    # MAC address validation pattern
    :local macAddr "00:11:22:AA:BB:CC";
    :local validMAC ($macAddr ~ "^([0-9A-Fa-f]{2}[:-]){5}([0-9A-Fa-f]{2})$");
    
    # Log file pattern matching
    :local logEntry "2024-11-30 10:15:30 [ERROR] Connection failed";
    :local isError ($logEntry ~ ".*\\[ERROR\\].*");     # true
    :local isWarning ($logEntry ~ ".*\\[WARNING\\].*"); # false
    
    # Extract information using pattern matching
    :local interfaceList [/interface print as-value];
    :foreach interface in=$interfaceList do={
        :local ifName ($interface->"name");
        
        # Check interface type by name pattern
        :if ($ifName ~ "^ether.*") do={
            /log info ($ifName . " is an Ethernet interface");
        } else={
            :if ($ifName ~ "^wlan.*") do={
                /log info ($ifName . " is a Wireless interface");
            } else={
                :if ($ifName ~ "^bridge.*") do={
                    /log info ($ifName . " is a Bridge interface");
                } else={
                    /log info ($ifName . " is another type of interface");
                };
            };
        };
    };
    
    # Pattern-based string replacement (using find and replace functions)
    :local inputText "The router IP is 192.168.1.1 and gateway is 192.168.1.254";
    :local processedText $inputText;
    
    # Simple find and replace (since RouterOS doesn't have full regex replace)
    :if ($processedText ~ "192\\.168\\.1\\.") do={
        /log info "Found private IP addresses in text";
        # Manual replacement logic would go here
    };
    
    /log info ("Pattern matching results:");
    /log info ("Has 'Hello': " . $hasHello);
    /log info ("Is backup file: " . $isBackup);
    /log info ("Is private IP: " . $isPrivateC);
}

Dynamic command execution

# Dynamic command construction and execution
{
    # Dynamic command building
    :local commandParts {"/interface"; "set"; "ether1"; "comment=\"Dynamic comment\""};
    :local fullCommand "";
    
    # Build command string
    :foreach part in=$commandParts do={
        :set fullCommand ($fullCommand . $part . " ");
    };
    
    /log info ("Would execute: " . $fullCommand);
    
    # Dynamic interface configuration
    :local configureInterface do={
        :local interfaceName $1;
        :local comment $2;
        :local enabled $3;
        
        # Build and execute command dynamically
        :if ($enabled) do={
            /interface set $interfaceName comment=$comment disabled=no;
        } else={
            /interface set $interfaceName comment=$comment disabled=yes;
        };
        
        /log info ("Configured interface " . $interfaceName);
    };
    
    # Use dynamic function
    [$configureInterface "ether1" "WAN Interface" true];
    [$configureInterface "ether2" "LAN Interface" false];
    
    # Dynamic rule creation based on conditions
    :local createFirewallRule do={
        :local chain $1;
        :local srcAddress $2;
        :local action $3;
        :local comment $4;
        
        # Dynamic rule creation
        /ip firewall filter add chain=$chain src-address=$srcAddress action=$action comment=$comment;
        /log info ("Created firewall rule: " . $chain . " " . $srcAddress . " -> " . $action);
    };
    
    # Create rules dynamically
    :local blockedIPs {"192.168.100.50"; "10.0.0.100"; "172.16.1.200"};
    :foreach blockedIP in=$blockedIPs do={
        [$createFirewallRule "input" $blockedIP "drop" ("Block suspicious IP: " . $blockedIP)];
    };
    
    # Dynamic VLAN creation
    :local createVLAN do={
        :local vlanId $1;
        :local vlanName $2;
        :local bridgeInterface $3;
        
        # Create VLAN interface
        /interface vlan add name=$vlanName vlan-id=$vlanId interface=$bridgeInterface;
        
        # Configure IP address
        :local ipAddress ("192.168." . $vlanId . ".1/24");
        /ip address add address=$ipAddress interface=$vlanName;
        
        /log info ("Created VLAN " . $vlanId . " with name " . $vlanName);
    };
    
    # Create multiple VLANs
    :local vlanConfigs {
        {id=10; name="VLAN10-Management"};
        {id=20; name="VLAN20-Users"};
        {id=30; name="VLAN30-Guest"}
    };
    
    :foreach vlanConfig in=$vlanConfigs do={
        :local vlanId ($vlanConfig->"id");
        :local vlanName ($vlanConfig->"name");
        [$createVLAN $vlanId $vlanName "bridge1"];
    };
    
    # Conditional command execution
    :local systemInfo [/system resource get];
    :local freeMemory ($systemInfo->"free-memory");
    :local totalMemory ($systemInfo->"total-memory");
    :local memoryUsage ((($totalMemory - $freeMemory) * 100) / $totalMemory);
    
    # Execute different commands based on system state
    :if ($memoryUsage > 90) do={
        /log error "Critical memory usage - clearing logs";
        /log clear;
    } else={
        :if ($memoryUsage > 75) do={
            /log warning "High memory usage - monitoring enabled";
            # Enable additional monitoring
        } else={
            /log info "Memory usage normal";
        };
    };
}

This comprehensive syntax reference covers all major aspects of RouterOS scripting language, providing the foundation for creating powerful automation scripts.

Last updated

Was this helpful?