How to get command output inside a script without printing it to the terminal?

I want to get the output of a “print” command inside a script into a variable. The [/command/print] construct gets the output in the variable, but it still also prints it.
E.g.:

/routing/bgp/session {
   :local prefixes;
   :foreach ses in=[find] do={
      :set $name [get $ses name]
      :set $remote [get $ses "remote.address"]
      :set $prefix [/routing/route/print count-only  where belongs-to="bgp-IP-$remote"]
      :set ($prefixes->$name) $prefix
   }
   :foreach name,prefix in=$prefixes do={
      :put "$name: $prefix"
   }
}

This script walks the active session list of BGP and reads the number of prefixes received on each of them (due to lack of RouterOS v7 providing this in the session info).
The script works OK (as of RouterOS 7.8beta2), but before it outputs the alphabetically sorted list of BGP peers and their prefixes, it first prints the prefix numbers in the random order the sessions are in the list. That is because the

:set $prefix [/routing/route/print count-only  where belongs-to="bgp-IP-$remote"]

not only puts the value in $prefix but also outputs it to the terminal.
How can I suppress that?

I do not reach to test belongs-to: no one value with count-only work on 7.7

Without count-only work as expected:

Work
/routing/route/print where belongs-to=“bgp-IP-xxx.xxx.xxx.xxx”

Do not work
/routing/route/print count-only where belongs-to=“bgp-IP-xxx.xxx.xxx.xxx”

This work, and do not print nothing on terminal:

:put [:len [/routing route find where belongs-to="bgp-IP-xxx.xxx.xxx.xxx"]]

Check this if it’s good enough:
/routing/bgp/session
{
:local prefixes ({})
:foreach session in=[find] do={
:local belongs [get $session “remote.address”]
:if ([:typeof $belongs]=“ip”) do={:set belongs “bgp-IP-$belongs”}
:if ([:typeof $belongs]=“ip6”) do={:set belongs “bgp-IP6-$belongs”}
:set ($prefixes->[get $session name]) [:len [/routing/route find where belongs-to=$belongs]]
}
:foreach name,prefix in=$prefixes do={
:put “$name: $prefix”
}
}

I know that that works, but it is extremely inefficient.
In 7.8beta2 (as I wrote) the “count-only where…” works OK and is a lot faster than fetching all the routes in an array and counting the members.
I am not looking for “how can I get the result in a different way” but for “how can I catch the output in a variable without it also appearing on the terminal”.
That is a general issue that could also become relevant in other contexts.

Try this…
:global tmpvar 0
/routing/bgp/session
{
:local prefixes ({})
:foreach session in=[find] do={
:local belongs [get $session “remote.address”]
:if ([:typeof $belongs]=“ip”) do={:set belongs “bgp-IP-$belongs”}
:if ([:typeof $belongs]=“ip6”) do={:set belongs “bgp-IP6-$belongs”}
:local jobID [:execute “:global tmpvar [/routing/route print count-only where belongs-to="$belongs"]”]
:while ([:len [/system/script/job find where .id=$jobID]] > 0) do={:delay 1s}
:set ($prefixes->[get $session name]) $tmpvar
}
:foreach name,prefix in=$prefixes do={
:put “$name: $prefix”
}
}
:set tmpvar

I consider that “too dirty”.
I hope there is a real solution…

You are insatiable… :laughing: :laughing: :laughing:

I will make a ticket. But currently the service desk server is down.

I think this is done with as-value.
Code will be:

:set prefix [/routing/route/print as-value count-only where belongs-to="bgp-IP-$remote"];

but nevertheless this also outputs it to terminal. Seems a bug when using as-value combined with count-only.

Instead, using as-value with bare print output works well:

[admin@MikroTik] > /routing/route/print where dst-address~"111"
Flags: A - ACTIVE; c, y - COPY
Columns: DST-ADDRESS, GATEWAY, AFI, DISTANCE, SCOPE, IMMEDIATE-GW
   DST-ADDRESS       GATEWAY        AFI  DISTANCE  SCOPE  IMMEDIATE-GW 
Ac 192.168.111.0/24  bridge-switch  ip4         0     10  bridge-switch

Usual print output.


[admin@MikroTik] > [/routing/route/print as-value where dst-address~"111"]

No :put, so no output, as expected.


[admin@MikroTik] > :local var [/routing/route/print as-value where dst-address~"111"]; :put $var
.id=*20144018;afi=ip4;distance=0;dst-address=192.168.111.0/24;gateway=bridge-switch;immediate-gw=bridge-
switch;scope=10

Output via :put, as expected.

Thank you for the hint! Now I seem to remember as-value but the docs of scripting are so inaccessible…
Indeed, it appears the combination of “as-value” and “count-only” does not work…
It looks like the programmer of the new routing was no well integrated with RouterOS conventions, the parameter structure is also very different from tradition.

Created #[SUP-106245]: count-only output always goes to terminal even when as-value is specified

I do not suggest you as-value + [:len ] because…

Yes, count-only and as-value are on conflict…

How about find+len?, since find only return obj ID.
Not sure about task speed.

Already solved on two way, on post #3, and on post #5, but user reply with this to numer #3:
http://forum.mikrotik.com/t/how-to-get-command-output-inside-a-script-without-printing-it-to-the-terminal/164006/1
and this for post #5
https://forum.mikrotik.com/viewtopic.php?p=981231#p981080

Before write a post, is better read all topic…

My bad :laughing:

On 7.8beta3 :execute is broken on purpose?..

Fix
:global tmpvar 0
/routing/bgp/session
{
:local prefixes ({})
:foreach session in=[find] do={
:local belongs [get $session “remote.address”]
:if ([:typeof $belongs]=“ip”) do={:set belongs “bgp-IP-$belongs”}
:if ([:typeof $belongs]=“ip6”) do={:set belongs “bgp-IP6-$belongs”}
:local jobID [:execute “:global tmpvar [/routing/route print count-only where belongs-to="$belongs"
file=/useless_change_that_broke_the_balls]]”
:while ([:len [/system/script/job find where .id=$jobID]] > 0) do={:delay 1s}
:set ($prefixes->[get $session name]) $tmpvar
}
:foreach name,prefix in=$prefixes do={
:put “$name: $prefix”
}
}
:set tmpvar

My SUP ticket was answered with “There will be major console improvements in the near future, we will include this feature too.”
So there is hope that we will soon see some improvement.