Community discussions

MikroTik App
 
obinoob
just joined
Topic Author
Posts: 10
Joined: Wed Nov 28, 2018 6:15 pm

Add array element inside for / foreach

Sun Dec 31, 2023 7:44 pm

I can't find a way to add an element to a global array inside a for loop.
The array content is being replaced by the last element.
:global interfaces;

:foreach i in=[/interface bridge port find where pvid=80] do={
    :local bport [interface bridge port get number=$i];
    :put ("$bport"->"interface");
    :set $interfaces ($interfaces $bport);
}

:put $interfaces;
Clearly Mikrotik scripting syntax is a pita; honestly, it's a simple array push function.
I really hope that someone can help me find out the reason why this isn't working properly.
 
User avatar
Amm0
Forum Guru
Forum Guru
Posts: 3509
Joined: Sun May 01, 2016 7:12 pm
Location: California

Re: Add array element inside for / foreach

Sun Dec 31, 2023 10:54 pm

Close. You need to declare the outer array & use parens+comma to concat values to the array.

:global interfaces [:toarray ""]

:foreach i in=[/interface bridge port find where pvid=80] do={
:local bport [/interface bridge port get number=$i];
:put ($bport->"interface");
:set $interfaces ($interfaces,$bport);
}
 
User avatar
rextended
Forum Guru
Forum Guru
Posts: 12014
Joined: Tue Feb 25, 2014 12:49 pm
Location: Italy
Contact:

Re: Add array element inside for / foreach

Mon Jan 01, 2024 4:18 am

Check errors... "$" after :set, useless ";" and $bport is not the interface/port name

Is not clear what is wanted at the end: one array with only all the interfaces name only (where pvid=80), or other?

Better this:
:global interfaces [:toarray ""]

/interface bridge port
:foreach i in=[find where pvid=80] do={
    :set interfaces ($interfaces,[get $i interface])
}

:put $interfaces
 
obinoob
just joined
Topic Author
Posts: 10
Joined: Wed Nov 28, 2018 6:15 pm

Re: Add array element inside for / foreach

Mon Jan 01, 2024 2:21 pm

Close. You need to declare the outer array & use parens+comma to concat values to the array.

:global interfaces [:toarray ""]

:foreach i in=[/interface bridge port find where pvid=80] do={
:local bport [/interface bridge port get number=$i];
:put ($bport->"interface");
:set $interfaces ($interfaces,$bport);
}
Unfortunately, it doesn't work! Just test it... it should be easy to make something like an array element push I guess.
 
obinoob
just joined
Topic Author
Posts: 10
Joined: Wed Nov 28, 2018 6:15 pm

Re: Add array element inside for / foreach

Mon Jan 01, 2024 2:23 pm

Check errors... "$" after :set, useless ";" and $bport is not the interface/port name

Is not clear what is wanted at the end: one array with only all the interfaces name only (where pvid=80), or other?

Better this:
:global interfaces [:toarray ""]

/interface bridge port
:foreach i in=[find where pvid=80] do={
    :set interfaces ($interfaces,[get $i interface])
}

:put $interfaces
Well, it's just a random exercise since I'm learning Mikrotik scripting, but the thing is to save every interface data configuration on an array while I'm looping through bridge interfaces with pvid=to some vlan id. Anyway, could you break it down for me, please? I'm a bit confused with the [get $i interface] :)
 
User avatar
rextended
Forum Guru
Forum Guru
Posts: 12014
Joined: Tue Feb 25, 2014 12:49 pm
Location: Italy
Contact:

Re: Add array element inside for / foreach

Mon Jan 01, 2024 3:05 pm

Just that?

example code

:global interfaces [/interface bridge port print detail as-value where pvid=80]

:put $interfaces
:put "$($interfaces->0->"interface") is on the bridge $($interfaces->0->"bridge")"
Obviously "put" print results on terminal only if something with pvid=80 exist...
 
obinoob
just joined
Topic Author
Posts: 10
Joined: Wed Nov 28, 2018 6:15 pm

Re: Add array element inside for / foreach

Mon Jan 01, 2024 4:38 pm

I want to understand how to push an element to an array inside a for / foreach loop!
Besides I can make use of the information generated inside a for loop and make something with it later.
I need to understand the mechanics of a simple element push to an array inside a for loop.
 
User avatar
Amm0
Forum Guru
Forum Guru
Posts: 3509
Joined: Sun May 01, 2016 7:12 pm
Location: California

Re: Add array element inside for / foreach

Mon Jan 01, 2024 5:28 pm

You "push" to an array by concatenating new values, as shown above. There is NO push/pop, only index and re-assignment. But you do have to declare the array when initializing it using [:toarray ""] as the value to create an array type.

More simple example:
:global interfaces [:toarray ""]
:foreach i in=(1,true,"three") do={ 
    :set interfaces ($interfaces,$i) 
}

:put $interfaces
# 1;true;three

:put [:len $interfaces]
# 3

:foreach j in=$interfaces do={ :put $j }
# 1
# true
# three


There some good basic scripting example here: https://wiki.mikrotik.com/wiki/Manual:S ... and_Tricks
 
obinoob
just joined
Topic Author
Posts: 10
Joined: Wed Nov 28, 2018 6:15 pm

Re: Add array element inside for / foreach

Mon Jan 01, 2024 5:51 pm

I can see now that Mikrotik scripting is the practical result of a collection of wild runs!
I thought that shell scripting was stupid enough but when compared is kinda refreshing...
The syntax is Dantesque and the complexity of possibilities is just outstanding in a bad way.

There must be a valid reason why this doesn't work, but I can't understand why since the iface local variable is reassigned in every loop with a new interface array! Perhaps the reason is the array architecture in itself.
:global interfaces [:toarray ""]

:foreach i in=[/interface bridge port find where pvid=80] do={
    :local iface [interface bridge port get number=$i];
    :set interfaces ($interfaces, $iface);
}

:put $interfaces;
 
User avatar
Amm0
Forum Guru
Forum Guru
Posts: 3509
Joined: Sun May 01, 2016 7:12 pm
Location: California

Re: Add array element inside for / foreach

Mon Jan 01, 2024 6:18 pm

There must be a valid reason why this doesn't work, but I can't understand why since the iface local variable is reassigned in every loop with a new interface array! Perhaps the reason is the array architecture in itself.
@rextended showed this part. The "get" either returns all values, or a specific one (like interface name):
 :local iface [interface bridge port get number=$i] interface;

You can see the difference if you "put" (print) to the console:
:put [/interface bridge port get 0]
:put [/interface bridge port get 0 interface]
 
obinoob
just joined
Topic Author
Posts: 10
Joined: Wed Nov 28, 2018 6:15 pm

Re: Add array element inside for / foreach

Tue Jan 02, 2024 2:27 pm

It prints interface data OK.
Array assignment doesn't work, it only saves the last interface.
:global interfaces [:toarray ""]

/interface bridge port
:foreach i in=[find where pvid=10] do={
    :put [get $i];
    :set interfaces ($interfaces,[get $i])
}

:put $interfaces
 
User avatar
rextended
Forum Guru
Forum Guru
Posts: 12014
Joined: Tue Feb 25, 2014 12:49 pm
Location: Italy
Contact:

Re: Add array element inside for / foreach

Tue Jan 02, 2024 3:31 pm

And it's perfectly logical, you can't have two keys with the same name in the same array...

:global example [:toarray ""]

:set example ($example,{"interface"="ether1";"arr1"="yes"})
:set example ($example,{"interface"="ether2";"arr2"="yes"})

:put $example

on results is present both arr1 and arr2, but only one interface, and obviously is the last set.

results code

arr1=yes;arr2=yes;interface=ether2

What you try to do, you want to do wrong.
If you do things randomly and don't read what I write, that's your business.
Fix it yourself.
 
obinoob
just joined
Topic Author
Posts: 10
Joined: Wed Nov 28, 2018 6:15 pm

Re: Add array element inside for / foreach

Tue Jan 02, 2024 4:33 pm

As I said earlier, it's an array-related architecture thing...
I now understand arrays in Mikrotik scripting do not work as I believed.
Anyways, thank you for pointing that out to me.
 
optio
Long time Member
Long time Member
Posts: 675
Joined: Mon Dec 26, 2022 2:57 pm

Re: Add array element inside for / foreach

Tue Jan 02, 2024 6:29 pm

What kind of key-value data type supports different value for same key in any programing/script language? How that will be even possible? Key must be unique. :)
Create main interfaces array and on each iteration add to it key-valye array for interface data. Then you can access values later by iterating $interfaces array or directly by index $interfaces->$index->"key", etc...
Like this for eg.:
:global interfaces [:toarray ""]

/interface bridge port
:foreach i in=[find where pvid=10] do={
    :put ([get $i]->"interface")
    :set interfaces ($interfaces, {[get $i]})
}

:put "-----------"

:foreach i in=$interfaces do={
    :put ($i->"interface")
}
 
User avatar
rextended
Forum Guru
Forum Guru
Posts: 12014
Joined: Tue Feb 25, 2014 12:49 pm
Location: Italy
Contact:

Re: Add array element inside for / foreach

Tue Jan 02, 2024 7:00 pm

Or simply, as already wrote on post #6....

example code

:global interfaces [/interface bridge port print detail as-value where pvid=10]

:put $interfaces

:foreach i in=$interfaces do={
    :put "$($i->"interface") is on the bridge $($i->"bridge")"
}
EDIT: Changed pvid
Last edited by rextended on Tue Jan 02, 2024 7:14 pm, edited 2 times in total.
 
optio
Long time Member
Long time Member
Posts: 675
Joined: Mon Dec 26, 2022 2:57 pm

Re: Add array element inside for / foreach

Tue Jan 02, 2024 7:07 pm

Yes, if there is no need for some other commands in iteration block while populating interfaces array...
 
User avatar
rextended
Forum Guru
Forum Guru
Posts: 12014
Joined: Tue Feb 25, 2014 12:49 pm
Location: Italy
Contact:

Re: Add array element inside for / foreach

Tue Jan 02, 2024 7:09 pm

Yes, if there is no need for some other commands in iteration block while populating interfaces array...
For sure, but the user, as example, want just obtain one array with all port interfaces data inside, and whay I have proposed is the fast way without cycles...
 
User avatar
Amm0
Forum Guru
Forum Guru
Posts: 3509
Joined: Sun May 01, 2016 7:12 pm
Location: California

Re: Add array element inside for / foreach

Tue Jan 02, 2024 7:43 pm

Stylistically, @rextended example in #6 is spot on. e.g. why use a foreach+find+get when there is a "/xxx print detail as-value" that get the key-value array for you in one command & then do whatever further operations on that KV array from print...
Or simply, as already wrote on post #6....
 
obinoob
just joined
Topic Author
Posts: 10
Joined: Wed Nov 28, 2018 6:15 pm

Re: Add array element inside for / foreach

Wed Jan 03, 2024 1:55 pm

Thank you all for your contributions, really very informative content!

Who is online

Users browsing this forum: No registered users and 7 guests