Community discussions

MikroTik App
 
Okietim
just joined
Topic Author
Posts: 15
Joined: Tue Feb 14, 2017 9:54 pm
Location: Oklahoma

":put" problem in scripting

Tue Jan 01, 2019 4:16 am

Unable to use :put to display contents of global var from within script.
Terminal cli works fine and can see that global var is changed from script, just no output on console
when initiated from script.
Using 6.43.7 and latest Winbox.
Have searched forum and google for answer without success.
Suggestions appreciated.
2018-12-31_17-56-01.jpg
console.jpg
You do not have the required permissions to view the files attached to this post.
 
mducharme
Trainer
Trainer
Posts: 1777
Joined: Tue Jul 19, 2016 6:45 pm
Location: Vancouver, BC, Canada

Re: ":put" problem in scripting  [SOLVED]

Tue Jan 01, 2019 4:38 am

This is normal behavior. If you want the script to print output while it runs, use the :log command which will output to the system log.
 
User avatar
sebastia
Forum Guru
Forum Guru
Posts: 1782
Joined: Tue Oct 12, 2010 3:23 am
Location: Antwerp, BE

Re: ":put" problem in scripting

Tue Jan 01, 2019 4:42 am

:put outputs in current session, but since the script is run in separate thread with it's own environment, the output won't be visible.
If you were to call on it from a shell you have open, it will output: "/system script run script1"
Another option: use :log
 
Okietim
just joined
Topic Author
Posts: 15
Joined: Tue Feb 14, 2017 9:54 pm
Location: Oklahoma

Re: ":put" problem in scripting

Tue Jan 01, 2019 6:15 pm

This is normal behavior. If you want the script to print output while it runs, use the :log command which will output to the system log.
Thank you mducharme! Now I know the answer.
 
Okietim
just joined
Topic Author
Posts: 15
Joined: Tue Feb 14, 2017 9:54 pm
Location: Oklahoma

Re: ":put" problem in scripting

Tue Jan 01, 2019 6:16 pm

:put outputs in current session, but since the script is run in separate thread with it's own environment, the output won't be visible.
If you were to call on it from a shell you have open, it will output: "/system script run script1"
Another option: use :log
Thank you sebastia! I'll give that a try.
 
stuartpbb
just joined
Posts: 8
Joined: Fri Oct 23, 2020 11:55 pm
Location: Portland, Oregon, USA

Re: ":put" problem in scripting

Thu Mar 17, 2022 4:35 am

Could the documentation be updated to reflect this?
https://wiki.mikrotik.com/wiki/Manual:Scripting

I just ran into the same problem and would have sworn it is a bug until I read this.
 
User avatar
Jotne
Forum Guru
Forum Guru
Posts: 3291
Joined: Sat Dec 24, 2016 11:17 am
Location: Magrathean

Re: ":put" problem in scripting

Fri Mar 18, 2022 3:24 pm

When you do have a script that run, lets say 00:00 every night. Where do you expect :put to show its output?
Do you have a terminal session open 24/7/365 and waiting for output? This is why we do have :log that sends output to log or syslog.
Data can also be sent to email, ftp, http, blink the led :) +++ (google email, telegram ++++++)

I do only use :put while I debug script to see what is going on when I test it in terminal.
 
User avatar
rextended
Forum Guru
Forum Guru
Posts: 11982
Joined: Tue Feb 25, 2014 12:49 pm
Location: Italy
Contact:

Re: ":put" problem in scripting

Fri Mar 18, 2022 6:18 pm

<useless>
Last edited by rextended on Sat Mar 19, 2022 11:47 pm, edited 1 time in total.
 
stuartpbb
just joined
Posts: 8
Joined: Fri Oct 23, 2020 11:55 pm
Location: Portland, Oregon, USA

Re: ":put" problem in scripting

Fri Mar 18, 2022 7:56 pm

Wow ... I did not expect the Mikrotik fanboy response back. It would be helpful to try and seek further clarification before jumping down someone's throat and saying they are flat wrong for asking that documentation be updated.

I should also have been a bit more clear. My exact problem is not with the scheduler, but with a script similar to this and :put not doing what is expected:
{
    :local data "this is a test";

    {
        :local foo [/system routerboard get board-name];
        :set data ($data . "\n" . $foo);
        :put "debug: added to data: $foo";
    }

    :local response [/tool fetch http-method=post http-data=$data output=user url="https://httpdump.io/eyxhj" as-value];

    :put "debug: response=$response";
}
I've tested this on RouterOS v6 and v7 and both will output the first :put, but not the second. My best guess is that the inner bracketed code (used to keep the :local foo variable scoped to that block) overrides the output stream such that the :put after the fetch does not make it to the console.

While reading the documentation I saw nothing that would describe why this would not work, hence my request that the documentation be updated to reflect the ways in which :put will not do what is intuitive (and how print statements work in other scripting languages).
 
User avatar
Larsa
Forum Guru
Forum Guru
Posts: 1041
Joined: Sat Aug 29, 2015 7:40 pm
Location: The North Pole, Santa's Workshop

Re: ":put" problem in scripting

Fri Mar 18, 2022 8:24 pm

Some dummy programmers use :put on script for retrieve values like { :global varx [:put "dummy"] } ... no comment...

But please "@rextended", stop ranting at folks that are not aware of these limitations!

The script engine is flawed in so many ways when it comes to manage stdout/stderr eg the inability to catch error messages and the lack error codes. The implementation of :put also went horribly wrong as it's not doing what ppl is expecting.
.
 
User avatar
rextended
Forum Guru
Forum Guru
Posts: 11982
Joined: Tue Feb 25, 2014 12:49 pm
Location: Italy
Contact:

Re: ":put" problem in scripting

Sat Mar 19, 2022 12:16 am

<useless>
Last edited by rextended on Sat Mar 19, 2022 11:48 pm, edited 4 times in total.
 
stuartpbb
just joined
Posts: 8
Joined: Fri Oct 23, 2020 11:55 pm
Location: Portland, Oregon, USA

Re: ":put" problem in scripting

Sat Mar 19, 2022 12:29 am

Some fix here and there and it works....

{
    :global data "this is a test"
    :global response ""
    :local foo [/system routerboard get board-name]
    :set data "$data\n$foo"
    :put "debug: added to data: $foo"
    [:parse ":global response [/tool fetch http-method=post http-data=\"$data\" output=user url=\"https://httpdump.io/eyxhj\" as-value]"]
    :delay 2s
    :put "debug: response=$[:tostr $response]"
}
Ok, however this code is now using global scoped variables instead of local. The intent is to use local scope to avoid saving state in the global environment that is not needed and keep local variables within the code block they relate to.

You are also using :parse to wrap the fetch and a :delay - why is this needed/where is this documented? The documentation & code examples I see (https://wiki.mikrotik.com/wiki/Manual:Tools/Fetch) show this example:

{
    :local result [/tool fetch url=http://10.0.0.1/disable_ether2.php as-value output=user];
    :if ($result->"status" = "finished") do={
        :if ($result->"data" = "0") do={
            /interface ethernet set ether2 disabled=yes;
        } else={
            /interface ethernet set ether2 disabled=no;
        }
    }
}

The code I originally used as an example works and $response is set (I have a fully functioning script working like this on ~30 routers running ROS v6 and v7), the debug :put after just is not outputting any data (which was the point of this thread).
 
User avatar
rextended
Forum Guru
Forum Guru
Posts: 11982
Joined: Tue Feb 25, 2014 12:49 pm
Location: Italy
Contact:

Re: ":put" problem in scripting

Sat Mar 19, 2022 12:58 am

<useless>
Last edited by rextended on Sat Mar 19, 2022 11:47 pm, edited 1 time in total.
 
User avatar
Amm0
Forum Guru
Forum Guru
Posts: 3253
Joined: Sun May 01, 2016 7:12 pm
Location: California

Re: ":put" problem in scripting

Sat Mar 19, 2022 1:03 am

While reading the documentation I saw nothing that would describe why this would not work, hence my request that the documentation be updated to reflect the ways in which :put will not do what is intuitive (and how print statements work in other scripting languages).
RouterOS script is "consitently, inconsistent" for sure. Likely some arguable bug here.

But not sure the problem with with the ":put", rather the string that it's trying to print. If string interpolation (aka "substitution") results in an error, which is what happens sometimes with - :put "value=$val" - if $val is an array... then, the string can fail and if it does nothing is returned . Since the string substitution happens before the :put, when the "stack unwinds" to the :put, it's an empty string. Basically it's best to need to make sure the variables your substituting are string, even an empty one, otherwise they may (or may not) "fail" with depending on exactly what type (num, array, ip, ip6, ip-prefix, etc., etc.), and string substitution fails, the entire string is null.

So I think the bigger issue is the response from /tool/fetch is an "array" type, and string interpolation is, well, "spotty" with arrays. Why/when, not sure - best not to use a variable array as a variable in a string. To fix your issue, you likely can just wrap it in a [:tostr $response] like so:
 :put "debug: response=$([:tostr $response])"
I think the extra "$([...])" around the variable creates a call on the stack, thus another "failure scope", so in the above if an error happens, the stack "unwinds" to the $([...]), so only that part be empty, not an error. In theory, ROS script should be smart enough to attempt the :tostr "cast" itself, and it may... but the $([...]) syntax acts like a "catch", at least in my observations. The :tostr part is needed since that will return an "empty string" not an error/nil/nothing.

Basically there is a lot undocumented, but the bigger issue is MT is "sloppy" in their variable types e.g. some CLI command will cast automatically, others won't; and some conversion aren't possible without hacks.
Last edited by Amm0 on Sat Mar 19, 2022 1:21 am, edited 1 time in total.
 
User avatar
rextended
Forum Guru
Forum Guru
Posts: 11982
Joined: Tue Feb 25, 2014 12:49 pm
Location: Italy
Contact:

Re: ":put" problem in scripting

Sat Mar 19, 2022 1:14 am

<useless>
Last edited by rextended on Sat Mar 19, 2022 11:48 pm, edited 1 time in total.
 
stuartpbb
just joined
Posts: 8
Joined: Fri Oct 23, 2020 11:55 pm
Location: Portland, Oregon, USA

Re: ":put" problem in scripting

Sat Mar 19, 2022 9:15 pm

Amm0 - thank you. Your reply has been the most helpful, and your assessment of RouterOS being consistently inconsistent seems spot on.

Using your suggestion and changing my original code example to use [:tostr] does work:
{
    :local data "this is a test";

    {{
    :local test [:toarray ""];
    :set ($test->"foo") "bar";
    :set ($test->"bar") "baz";
    
    :put "debug #1: test=$test";
    :put ("debug #2: test(concat)=" . $test);
    :put "debug #3: test(tostr)=$[:tostr $test]";
    :put "debug #4: test="; :put $test;
}

        :local foo [/system routerboard get board-name];
        :set data ($data . "\n" . $foo);
        :put "debug: added to data: $foo";
    }

    :local response [/tool fetch http-method=post http-data=$data output=user url="https://httpdump.io/eyxhj" as-value];

    :put ("debug: typeof response=" . [:typeof $response]);
    :put ("debug: response=" . [:tostr $response]);
}

The explanation that :put is choking on the array fits for the consistently inconsistent behavior of the OS. I created a bit more in depth test to see what works and what does not:
{
    :local test [:toarray ""];
    :set ($test->"foo") "bar";
    :set ($test->"bar") "baz";
    
    :put "debug #1: test=$test";
    :put ("debug #2: test(concat)=" . $test);
    :put "debug #3: test(tostr)=$[:tostr $test]";
    :put "debug #4: test="; :put $test;
}
The first and second :put do not output anything at all, the third and fourth both do. That the fourth does is, to me, inconsistent behavior - RouterOS seems to implicitly convert an array to a string when that is the only data being output, yet cannot do the same implicit conversion (and throws no error or warning) when string concatenation is involved.

My experience with other languages is that an implicit conversion of a non-string to string either works similar to how #4 does, or that they convert something like an array to a static string such as "{array}" in the output. Losing all the output is (again, to me) inconsistent and takes extra time trying to figure out what is going on and debug the issue.

In any case, I think I've hijacked the original thread enough - thank you for the insights & the clarity!
 
User avatar
Amm0
Forum Guru
Forum Guru
Posts: 3253
Joined: Sun May 01, 2016 7:12 pm
Location: California

Re: ":put" problem in scripting

Sat Mar 19, 2022 11:01 pm

Well my point was it ain't the poor ":put" statement to blame. Basically you with variable substitution a "best practice" would be just to "cast", all sorts of cases it's unnecessary. But as noted elsewhere error handling in script is also limited, so you want to avoid getting an error in the first place.

But the "." and arrays are more complex. An array can store a few different things (e.g. key-value-pairs, or list of str/num/etc, or functions, or mixture of any), and what it stores effects how the :put will work. If you have an array of just strings, it should work might work close to like you'd expect (still not quite I suspect).
:global strarr {"abc"; "def"}
:put [len $strarr]
# 2
:put [typeof $strarr]
array
:put "strarr=$strarr"
#strarr=abc;strarr=def
:global strstrarr "strarr=$strarr"
:put [len $strstrarr]
#2
:put [typeof $strstrarr]
#array
:put $strstrarr
#strarr=abc;strarr=def
:put ($strstrarr->0)
#strarr=abc
:put "onemorelevel=$strstrarr"
#onemorelevel=strarr=abc;onemorelevel=strarr=def
These all work since the types within the array are "normal" like str (or num be same). But like your example and this one below, arrays can store key-value-pairs. And when then do, that's when the string interpolation fails.
 :global arrarr {a=1;b="txt"}
:put "$arrarr"
#a=1;b=txt
:put "some text $arrarr"
# ### no output as seen elsewhere in thread ### 

How the "dot . operator" works with array is actually documented in the help (e.g. that it acts like functional programming "set apply" operator), but why the first example repeated the text. Extending that, if you have a string then an array, script can infer the "dot operator" if it see a string token followed by an array token like in "text$myarray", which likely why that does same thing.

Anyway, I'll run with consistently, inconsistent. At some level, most things they do make sense – it just the really are missing a few primitives and types are asymmetric.
 
User avatar
Amm0
Forum Guru
Forum Guru
Posts: 3253
Joined: Sun May 01, 2016 7:12 pm
Location: California

Re: ":put" problem in scripting

Sat Mar 19, 2022 11:29 pm

One more thing. On the docs & fairness to MT, there is an older "Tips and Tricks", that is linked from the current Scripting manual here: https://wiki.mikrotik.com/wiki/Manual:S ... and_Tricks
It has a section titled "Be careful when adding array to string" that might describe this better.

Who is online

Users browsing this forum: No registered users and 21 guests