Difference between revisions of "Manual:Scripting Tips and Tricks"

From MikroTik Wiki
Jump to: navigation, search
(Be careful when adding array to string)
(Accessing global variable from function)
Line 140: Line 140:
 
global var=test
 
global var=test
 
</pre>
 
</pre>
 +
 +
 +
 +
===Always use unique variable names===
 +
 +
One of the most common scripting mistakes that most users are doing is not using unique varible names, for example,
 +
variable defined in function has the same name as globally defined variable, which leads to unexpected result:
 +
<pre>
 +
:global my2 "123"
 +
 +
:global myFunc do={ :global my2; :put $my2; :set my2 "lala"; :put $my2 }
 +
$myFunc my2=1234
 +
:put "global value $my2"
 +
</pre>
 +
Output will be:
 +
<pre>
 +
1234
 +
lala
 +
global value 123
 +
</pre>
 +
 +
 +
Another common case is when user defined variable have the same name as RouterOS built in variable, for example, we want to print route with dst address defined in variable:
 +
 +
<pre>
 +
[admin@1p_DUT_wAP ac] /ip route> :global "dst-address" "0.0.0.0/0"
 +
[admin@1p_DUT_wAP ac] /ip route> print where dst-address=$"dst-address"
 +
Flags: X - disabled, A - active, D - dynamic, C - connect, S - static, r - rip, b - bgp, o - ospf, m - mme,
 +
B - blackhole, U - unreachable, P - prohibit
 +
#      DST-ADDRESS        PREF-SRC        GATEWAY            DISTANCE
 +
0 ADS  0.0.0.0/0                          10.155.136.1              1
 +
1 ADC  10.155.136.0/24    10.155.136.41  ether1                    0
 +
 +
</pre>
 +
 +
Obviously result is not as expected, simple solution, use unique variable name:
 +
<pre>
 +
[admin@1p_DUT_wAP ac] /ip route> :global myDst "0.0.0.0/0"
 +
[admin@1p_DUT_wAP ac] /ip route> print where dst-address=$myDst           
 +
Flags: X - disabled, A - active, D - dynamic, C - connect, S - static, r - rip, b - bgp, o - ospf, m - mme,
 +
B - blackhole, U - unreachable, P - prohibit
 +
#      DST-ADDRESS        PREF-SRC        GATEWAY            DISTANCE
 +
0 ADS  0.0.0.0/0                          10.155.136.1              1
 +
</pre>
 +
 
{{Cont}}
 
{{Cont}}
  

Revision as of 14:32, 24 August 2018

Version.png

Applies to RouterOS: any

How to define empty array

Get values for properties if 'get' command is not available

For example, how do you get usable output for scripting from /interface wireless info hw-info command? Use as-value:

[admin@1p_DUT_wAP ac] /interface wireless info> :put [hw-info wlan1 as-value ]
ranges=2312-2732/5/b;g;gn20;gn40;2484-2484/5/b;g;gn20;gn40;rx-chains=0;1;tx-chains=0;1

Output is 1D array so you can easily get interested property value

[admin@1p_DUT_wAP ac] /interface wireless info> :put ([hw-info wlan1 as-value ]->"tx-chains")      
0;1

Always check what value and type command returns

Lets say we want to get gateway of specific route using as-value, if we execute following command it will return nothing

[admin@rack1_b36_CCR1009] /ip address> :put ([/ip route print as-value where gateway="ether1"]->"gateway") 


Command assumes that output will be 1D array from which we could extract element gateway.

At first lets check if print is actually find anything:

[admin@rack1_b36_CCR1009] /ip address> :put ([/ip route print as-value where gateway="ether1"])  
.id=*400ae12f;distance=255;dst-address=111.111.111.1/32;gateway=ether1;pref-src=111.111.111.1

So obviously there is something wrong with variable itself or variable type returned. Lets check it more closely:

[admin@rack1_b36_CCR1009] /ip address> :global aa ([/ip route print as-value where gateway="ether1"
])       
[admin@rack1_b36_CCR1009] /ip address> :environment print 
aa={{.id=*400ae12f; distance=255; dst-address=111.111.111.1/32; gateway={"ether1"}; pref-src=111.11
1.111.1}}

Now it is clear that returned value is 2D array with one element. So the right sequence to extract gateway will be:

  • get 2d array
  • get first element
  • get "gateway" from picked element
[admin@rack1_b36_CCR1009] /ip address> :put ([:pick [/ip route print as-value where gateway="ether1"] 0]->"gateway")  
ether1

Be careful when adding array to string

If you want to print an array or add an array to existing string, be very careful as it may lead to unexpected results. For example ,we have array with two elements and we want to print the array value on screen:

[admin@1p_DUT_wAP ac] /> :global array {"cccc", "ddddd"}
[admin@1p_DUT_wAP ac] /> :put ("array value is: " . $array )       
array value is: cccc;array value is: ddddd

Obviously this is not what we expected, because what . does is adds string to each array element and then prints the output. Instead you need to convert to string first:

[admin@1p_DUT_wAP ac] /> :put ("array value is: " . [:tostr  $array] )
array value is: cccc;ddddd


Get/Set unnamed elements in array

Lets say we have an array of elements { "el1"; "el2"; "el3" }. It is possible to pick elements of an array with pick command, but is not so neat as syntax below:

[admin@1p_DUT_wAP ac] /> :global test { "el1"; "el2"; "el3" }   
[admin@1p_DUT_wAP ac] /> :put ($test->1)                     
el2

The same syntax can be used to set values:

[admin@1p_DUT_wAP ac] /> :set ($test->2) "el3_changed"
[admin@1p_DUT_wAP ac] /> :environment print 
test={"el1"; "el2"; "el3_changed"}


Set element value in 2D array

Syntax used in example above can also be used to set element value in 2D array:

[admin@1p_DUT_wAP ac] /> :global test {{"11";"12";"13"};{"21";"22";"23"}}   
[admin@1p_DUT_wAP ac] > :set ($test->1->1) "22_changed"
[admin@1p_DUT_wAP ac] > :put [($test->1->1)]           
22_changed
[admin@1p_DUT_wAP ac] > :environment print  
test={{"11"; "12"; "13"}; {"21"; "22_changed"; "23"}}

Accessing global variable from function

Logically you would think that globally defined variables should be accessible in functions too, but that is not really the case. Lets see an example:

:global myVar "test"
:global myFunc do={
  :put "global var=$myVar"
}
[$myFunc]

Output is:

global var=

So obviously global variable is not accessible directly. To make it work we need do declare global variable inside the function:

:global myVar "test"
:global myFunc do={
  :global myVar;
  :put "global var=$myVar"
}
[$myFunc]

Output:

global var=test


Always use unique variable names

One of the most common scripting mistakes that most users are doing is not using unique varible names, for example, variable defined in function has the same name as globally defined variable, which leads to unexpected result:

:global my2 "123"

:global myFunc do={ :global my2; :put $my2; :set my2 "lala"; :put $my2 }
$myFunc my2=1234
:put "global value $my2"

Output will be:

1234
lala
global value 123


Another common case is when user defined variable have the same name as RouterOS built in variable, for example, we want to print route with dst address defined in variable:

[admin@1p_DUT_wAP ac] /ip route> :global "dst-address" "0.0.0.0/0"
[admin@1p_DUT_wAP ac] /ip route> print where dst-address=$"dst-address" 
Flags: X - disabled, A - active, D - dynamic, C - connect, S - static, r - rip, b - bgp, o - ospf, m - mme, 
B - blackhole, U - unreachable, P - prohibit 
 #      DST-ADDRESS        PREF-SRC        GATEWAY            DISTANCE
 0 ADS  0.0.0.0/0                          10.155.136.1              1
 1 ADC  10.155.136.0/24    10.155.136.41   ether1                    0

Obviously result is not as expected, simple solution, use unique variable name:

[admin@1p_DUT_wAP ac] /ip route> :global myDst "0.0.0.0/0"
[admin@1p_DUT_wAP ac] /ip route> print where dst-address=$myDst             
Flags: X - disabled, A - active, D - dynamic, C - connect, S - static, r - rip, b - bgp, o - ospf, m - mme, 
B - blackhole, U - unreachable, P - prohibit 
 #      DST-ADDRESS        PREF-SRC        GATEWAY            DISTANCE
 0 ADS  0.0.0.0/0                          10.155.136.1              1

[ Top | Back to Content ]