Page 1 of 1

Type "nothing"

Posted: Sun Dec 09, 2018 2:36 am
by iperezandres
With this code:
:global X1 1
:global type1 [:typeof $X1]
The type of X1 is "num".

But with this other code:
:global i 1
:execute ":global X$i"
:global type2 [:typeof $X1]
The type of X1 is "nothing" instead of "num", with X1 being previously declared as a global variable from other script.

¿Why the nothing type, if X1 already existed?

if you need to know, what I am trying to do is something like this, to reuse several global variables already declared from another script:
:for i from=1 to=4 do={
   :execute ":global IP$i"
}

Re: Type "nothing"

Posted: Sun Dec 09, 2018 5:52 am
by 2frogs
All variables have to be declared that are used in the script, global or not, declared in other scripts or not.

Re: Type "nothing"

Posted: Sun Dec 09, 2018 10:26 am
by Jotne
As 2frogs write, you need to declare it like this.
:global testvarr
If you add something after, you will overwrite current data.

So if in one script you have some like this:
:global testvar "my data"
Then run this in an other script:
:global testvar
:put $testvar
will give
my data

Re: Type "nothing"

Posted: Sun Dec 09, 2018 1:03 pm
by sebastia
The question is why is the typing changing. Declaring a variable shouldn't be doing that.

Tried to replicate, but can't:

2 sessions/terminals

1. run first
[Sebastian@firewall] > :global X1 1
[Sebastian@firewall] > :put [:typeof $X1] 
num

2 run second
[Sebastian@firewall] > {:local i 1; :execute ":global X$i"; :put [:typeof $X1]}       
num

Re: Type "nothing"

Posted: Sun Dec 09, 2018 1:21 pm
by Jotne
I do not understand your problem. Test this.

First script, storing data
{
:put "storing global variables"
:global text "my text"
:global number 2345
:put "Test of text: $text = $([:typeof $text])"
:put "Test of number: $number = $([:typeof $number])"
}

storing global variables
Test of text: my text = str
Test of number: 2345 = num

Second script, using data
{
:put "using global variables"
:global text
:global number
:put "Test of text: $text = $([:typeof $text])"
:put "Test of number: $number = $([:typeof $number])"
}

using global variables
Test of text: my text = str
Test of number: 2345 = num
Nothing changes, string is str and number is num.


Edit test your script.
admin@941-2nD] > :global X1 123
[admin@941-2nD] >
[admin@941-2nD] > {
{... :local i 1;              # set local variable i=1
{... :execute ":global X$i";  # declare global variable X1, since i=1
{... :put [:typeof $X1];      # Test what type of data X1
{... }
num
[admin@941-2nD] >
[admin@941-2nD] > :global X1 "test"
[admin@941-2nD] >
[admin@941-2nD] > {
{... :local i 1;              # set local variable i=1
{... :execute ":global X$i";  # declare global variable X1, since i=1
{... :put [:typeof $X1];      # Test what type of data X1
{... }
str

Re: Type "nothing"

Posted: Sun Dec 09, 2018 3:13 pm
by iperezandres
It works from the terminal but it does not work from a script.
This code in the terminar returns "type=num":
[admin@MK] > {
{... :local i 1;              
{... :execute ":global TrafWAN$i";
{... :global type [:typeof $TrafWAN1];
{... }   
But the same code in a script returns "type=nothing":
:local i 1;
:execute ":global TrafWAN$i";
:global type [:typeof $TrafWAN1];
In both cases the variable $TrafWAN1 already existed as num type and value "123".

Why the same code is being treated differently in the terminal than in the script? Shouldn't be the same?

Re: Type "nothing"

Posted: Sun Dec 09, 2018 5:06 pm
by Jotne
I do now understand what you try to do.

Declaring global variable works as it suppose to do.
But i fails when you try to declare it indirectly using a variable.
It may be an other way to do it, will test some.
But this seems to be as support case for MT. Send them an email at support@mikrotik.com

Re: Type "nothing"

Posted: Sun Dec 09, 2018 5:12 pm
by iperezandres
Thank you Jotne, I will keep on trying different approaches and I will try support@mt as well.
Keep you posted!

Re: Type "nothing"

Posted: Sun Dec 09, 2018 5:12 pm
by sebastia
Maybe it's a case of permissions...

Who has set the original variable? With what permissions?
And what permissions does the script have?

see also viewtopic.php?f=9&t=109696&hilit=script ... permission

Re: Type "nothing"

Posted: Sun Dec 09, 2018 5:19 pm
by iperezandres
Don't think that is the problem, I tried as admin with every policy selected, and same result. Unless the terminal runs the code with different permissions; that, I don't know.

Re: Type "nothing"

Posted: Sun Dec 09, 2018 6:49 pm
by Jotne
Possible solution found.
Do not store you data inn to different global variable, but store all in one global array.

Eks
:global x aa,bb,cc,dd,ee,ff
Script test using indirect variable to get array value.
:local i 2;
:global x
:put [:pick $x $i]
run test
cc

Re: Type

Posted: Sun Dec 09, 2018 6:57 pm
by iperezandres
Mmm, interesting approach! Let me give it a try... Thanks!

Re: Type "nothing"

Posted: Sun Dec 09, 2018 7:06 pm
by Jotne
Edit:

You can set a specific field in the array like this:
:set ($myArray->2) 44
Sets 3rd field (fist field=0) to 44

So for example above
:global x aa,bb,cc,dd,ee,ff
Script test
:local i 2
:global x
:put [:pick $x $i]
:set ($x->$i) "QQ"
:put [:pick $x $i]
Result
run test
cc
QQ

Re: Type "nothing"

Posted: Sun Dec 09, 2018 8:26 pm
by Jotne
Even closer to your request
:global x {test1=76;test2=276;test3=387}
/system script> :environment print
x={test1=76; test2=276; test3=387}
script test
:local i 2;
:global x
:put ($x->"test$i")
run test
276
Another example using part of the inner variable with an index
:for a from=1 to=[:len $x] do={:put ($x->"test$a")}
76
276
387

Re: Type "nothing"  [SOLVED]

Posted: Fri Dec 28, 2018 12:14 pm
by Frostbyte
Declaring global variable works as it suppose to do.
But i fails when you try to declare it indirectly using a variable.
Just wanted to chime in on this one.

First, as others already described - you need to declare the variable again (global) in order for your script to "read" it.
If you have a nested function that also uses that variable, you have to re-declare it again inside the nested function as well. (Even if it's declared outside and above it)

The problem begins with the usage of the "execute" command. Execute runs the supplied command in a sub-shell - so you get no interaction with it whatsoever.
Allow me to take it step by step as to what happens here:
:local i 1; <--- local variable "i" is declared with a value of 1, being local means it can only be read by the region it's been put into (script, curly braces, etc).
:execute ":global TrafWAN$i"; <--- $i is resolved into value 1, so the string that's getting executed is ":global TrafWAN1". But this command was ran in a sub-shell, once it completes - POOF! Everything's gone! ..think of it more like calling another script, from your script, to do stuff for you. You cannot interact with it, it only executes whatever is enclosed in its quotes.
:global type [:typeof $TrafWAN1]; <--- the command "typeof" attempts to fetch the type of $TrafWAN1 which at this point hasn't been declared in the script and is therefore "unknown".
The reason this works on the terminal and not on the script, is that on the terminal you can "read" the global variables without having to declare them prior.
Plus, on the terminal version of your code, you can even skip the "execute" line altogether because it offers virtually nothing to you. (it just executes a global declaration and exits)

Re: Type "nothing"

Posted: Fri Dec 28, 2018 12:22 pm
by iperezandres
Such a good explanation, that was the feeling I was getting from my tests but it is great to have a confirmation.

The thing is that "execute" is a very useful command, even though it has its limitations, and lets you manage code in a dynamically fashion.

Thanks!
Declaring global variable works as it suppose to do.
But i fails when you try to declare it indirectly using a variable.
Just wanted to chime in on this one.

First, as others already described - you need to declare the variable again (global) in order for your script to "read" it.
If you have a nested function that also uses that variable, you have to re-declare it again inside the nested function as well. (Even if it's declared outside and above it)

The problem begins with the usage of the "execute" command. Execute runs the supplied command in a sub-shell - so you get no interaction with it whatsoever.
Allow me to take it step by step as to what happens here:
:local i 1; <--- local variable "i" is declared with a value of 1, being local means it can only be read by the region it's been put into (script, curly braces, etc).
:execute ":global TrafWAN$i"; <--- $i is resolved into value 1, so the string that's getting executed is ":global TrafWAN1". But this command was ran in a sub-shell, once it completes - POOF! Everything's gone! ..think of it more like calling another script, from your script, to do stuff for you. You cannot interact with it, it only executes whatever is enclosed in its quotes.
:global type [:typeof $TrafWAN1]; <--- the command "typeof" attempts to fetch the type of $TrafWAN1 which at this point hasn't been declared in the script and is therefore "unknown".
The reason this works on the terminal and not on the script, is that on the terminal you can "read" the global variables without having to declare them prior.
Plus, on the terminal version of your code, you can even skip the "execute" line altogether because it offers virtually nothing to you. (it just executes a global declaration and exits)