I wanted to capture the WAN address of my HAP AX3 router.
I can see the address by issuing the print command.
[@MikroTik] > ip address/print proplist=address where interface=ether1_WAN
Flags: D - DYNAMIC
Columns: ADDRESS
# ADDRESS
2 D 1.2.3.4/21
Now, I wanted to isolate the address, something like “grep -o”.
Is there a way to print a single value from a console output?
Is there a regex function?
In the “find”, “print where”, or in an :if like statement you can use the tilde to match a variable or attribute against a regex: attribute~“.*”
Only boolean matches and no grouping or replacement however.
So in the find shown above, you could search for anything that starts with “ether1”
:global wanIP [/ip/address get [find interface~"^ether1"] address]
(although there is also default-name= on /interface to match on too)
And, yes, the ; at end is unneeded too. Newline ends a command (unless the backtick \ is used at end which mean the next line is part of this one). Semicolons only need if you want multiple commands on one line. So in your :do {} they are needed (since you don't have newlines). But there is no need to END a command with a semi-colon AND newline.
FWIW we're picky around here... since RouterOS script is also picky sometimes.
Dorky side note: RouterOS has types too. So as a technical point “:return [:toip [:pick $currentIPv4 0 [:find $currentIPv4 “/” -1]]]” in above be more accurate but in nearly all contexts RouterOS will “cast” a string to IP if needed internally… so keep IP as a string likely easier in practice.
And, above code could fail, if an interface= had multiple IP address associated with it (e.g. “multihoming”).
But… it’s often’s better if a script fails immediately, than “catching” the on-error=. If something else further needs that IP address, which is likely, you’ve just moved what is going to fail & it’s may hard to know that the issue is the IP is empty.
Yup. :error will stop the script, and print message to the CLI/console. While the /log handles the case if same script run in background. So that combo covers both CLI and /system/script.
But often it better to just add some more :if (error-condition) do={:error …} checks along the way. And if something actually goes to the on-error={}, your still left wondering what may have cause the error…
For example, in your code above (or my function too), using “[find interface=$wanInt]”… if you have one interface that has 2 /ip/address records – that cause an error on the “get”. But… so would if there 0 /ip/address found for an interface. And… your on-error={} have no clue as which of those two case that was. Now a lot of times, the “why” doesn’t matter too. But PREVENTING anything from going to the on-error= is a good idea.
How to manage errors without using shitty on-error.
{
:global ipfrominterface do={
:local iface [:tostr $1]
:local ifadd 0.0.0.0
/interface
:if ([:len [find where name=$1]] != 1) do={:return “interface >$iface< do not exist”}
/ip address
:local temp [find where interface=$iface]
:if ([:len $temp] = 0) do={:return “interface >$iface< do not have one address”}
:if ([:len $temp] > 1) do={:return “interface >$iface< have more than one address”}
:local ifadd [get $temp address]
:return [:toip [:pick $ifadd 0 [:find $ifadd “/” -1]]]
}
:local iface "ether1"
:local ifaceadd [$ipfrominterface $iface]
:if ([:type $ifaceadd] = "ip") do={
:put "The IP address of $iface is $ifaceadd"
:log info "The IP address of $iface is $ifaceadd"
} else={
:put "ERROR: $ifaceadd"
:error $ifaceadd
}