Community discussions

MikroTik App
 
Josephny
Member
Member
Topic Author
Posts: 495
Joined: Tue Sep 20, 2022 12:11 am

Frustrated trying to create a script

Fri Sep 29, 2023 6:22 pm

Can someone please tell me what I'm doing wrong (or all the things I'm doing wrong):
/system
:local cdate [clock get date] 
:local yyyy  [:pick $cdate 0  4]
:local MM    [:pick $cdate 5  7]
:local dd    [:pick $cdate 8 10]
:local identitydate "$[identity get name]_$yyyy-$MM-$dd"

/file print file=fileup 

#/file remove fileup.txt

:local fileup "$[$identitydate].txt-dynamicdata"

/ip/cloud print file=cloud
/ip/dhcp-server/lease print file=leases
/interface/bridge/host print file=hosts
/interface/wireless/registration-table print file=registrations

:local cloudcontents [/file get $cloud contents]
:local leasescontents [/file get $leases contents]
:local hostscontents [/file get $hosts contents]
:local registrationscontents [/file get $registrations contents]

:local fileupcontents "$[$cloudcontents] . "\r\n" . $[$leasescontents] . "\r\n" . $[$hostscontents] . "\r\n" . $[$registrationscontents]"

/file print $fileup contents = $[$fileupcontents]

#/tool fetch upload=yes mode=ftp ascii=no src-path="/fileup.txt" dst-path="/mikrotik-backups/fileup.txt" address=192.168.2.22 port=21 user=mikrotik password=mikrotik
 
User avatar
Amm0
Forum Guru
Forum Guru
Posts: 3506
Joined: Sun May 01, 2016 7:12 pm
Location: California

Re: Frustrated trying to create a script

Fri Sep 29, 2023 7:22 pm

You're incorrectly using "string interpolation" is your main issue...
:local fileup "$[$identitydate].txt-dynamicdata"
with $identitydate being a string variable, so should be following:
:local fileup "$($identitydate).txt-dynamicdata"
or
:local fileup "$identitydate.txt-dynamicdata"
should work.
... and mistake is repeated throughout.

Essentially DO NOT USE square brackets to access a variable! Square bracket run commands/functions and what returned is put into the string. String and numbers in variable are not functions/commands, so they don't "return" anything – only store. So all the place you're putting a varable into a string use "my string is $mystr".

Perhaps an example help:


{
:local myvar Mikrotik
:local "my-var-kabab" Mikrotik

:put "a command's return value using brackets: $[/system identity get name]"

:put " vs"

:put "using a simple variable in string is just a dollar sign and var name, so: $myvar"
:put " BUT for more complex names or part of array or variables 'touching', you need use a 'grouping' \$(...), here: $($"my-var-kabab")"

:put "* as shown, use CAN use unescaped quotes INSIDE the grouping syntax \$(parenthesis) "
:put " note above use the dollar sign needs to be escaped to be printed \$"
:put " along with backsplash that escape the dollar too, so \\\$ if we wanted the backsplash in output"

:global myarray {"mykey":"ex"; "mystr"="sometext"}
:put "now if the variable your including in string is an 'array' type... it also uses the 'dollar grouping' with parenthesis syntax"

:put "so to get the mystr value inside myarray that just $($myarray->"mystr")"

:put "* IMPORARTANTLY array types SHOULD NOT be used DIRECTLY in a string"
:put " while \$myarray in string is allowed, and may work, just complex logic gets involved always using '\$[:tostr $myarray]' avoid this"
:put " so to :put an ENTIRE array, you start with the :tostr COMMAND, like: $[:tostr $myarray] "
:put " note the :tostr is a command that RETURNS, so why it uses square brackets"
}
a command's return value using brackets: bigdude
vs
using a simple variable in string is just a dollar sign and var name, so: Mikrotik
BUT for more complex names or part of array or variables 'touching', you need use a 'grouping' $(...), here: Mikrotik
* as shown, use CAN use unescaped quotes INSIDE the grouping syntax $(parenthesis)
note above use the dollar sign needs to be escaped to be printed $
along with backsplash that escape the dollar too, so \$ if we wanted the backsplash in output
now if the variable your including in string is an 'array' type... it also uses the 'dollar grouping' with parenthesis syntax
so to get the mystr value inside myarray that just sometext
* IMPORARTANTLY array types SHOULD NOT be used DIRECTLY in a string
while $myarray in string is allowed, and may work, just complex logic gets involved always using '$[:tostr ex]' avoid this
so to :put an ENTIRE array, you start with the :tostr COMMAND, like: ex;mystr=sometext
note the :tostr is a command that RETURNS, so why it uses square brackets
Last edited by Amm0 on Fri Sep 29, 2023 7:45 pm, edited 1 time in total.
 
pe1chl
Forum Guru
Forum Guru
Posts: 10248
Joined: Mon Jun 08, 2015 12:09 pm

Re: Frustrated trying to create a script

Fri Sep 29, 2023 7:44 pm

Also, I would warn against trying to do too much in a single expression. At some point it just won't work and there are no ways to debug it.
It is safest to move some calculated value into a variable first before using it inside another expression, and also best to use the . string concat operator instead of having variable substitutions inside quoted strings.
So use the method you have used to set "fileupcontents", not the method you used to set "fileup".
(aside from having [] instead of () )
 
User avatar
Amm0
Forum Guru
Forum Guru
Posts: 3506
Joined: Sun May 01, 2016 7:12 pm
Location: California

Re: Frustrated trying to create a script

Fri Sep 29, 2023 7:59 pm

also best to use the . string concat operator instead of having variable substitutions inside quoted strings.
Fair point about "dot concatenation". I do use both myself. More :local var in above code would also clean it up and make more "debuggable" with the intermediate values.


But it is a "pick your poison" situation — there be dragons with arrays and string – wherever you turn.
e.g.
:global myarraymap {"key1"="text1";"key2"="text2"}
:global myarraylist ("str1","str2")
:global mystr "myglobalvar"
:put ($myarraylist.$mystr) 
        # output:     "str1myglobalvar;str2myglobalvar"
:put ($myarraymap.$mystr) 
        # outputs empty newline
 
User avatar
Amm0
Forum Guru
Forum Guru
Posts: 3506
Joined: Sun May 01, 2016 7:12 pm
Location: California

Re: Frustrated trying to create a script

Fri Sep 29, 2023 8:26 pm

FWIW my "frustration in trying to create a script" is more pedantic: i want '.' to work with functions, so it acts like a map() to modify the array, that really cleanup some scripts. But ain't putting much hope in that.

Just for example of how "dot concatenation" works with array and functions today, and also how square brackets change things...:
:global myarraylist ("text1","text2")
:global myfunction do={:return "something $1 $0"}      
:put ($myarraylist.$myfunction)      
# text1;text1(code);text2;text2(code)                               
:put ($myarraylist.[$myfunction])
# text1something  $myfunction;text2something  $myfunction
 
Josephny
Member
Member
Topic Author
Posts: 495
Joined: Tue Sep 20, 2022 12:11 am

Re: Frustrated trying to create a script

Sat Sep 30, 2023 1:30 am

Thank you very much.

I have a much better understand of when to use brackets now.

But, I still can't get this script to work:
/system
:local cdate [clock get date] 
:local yyyy  [:pick $cdate 0  4]
:local MM    [:pick $cdate 5  7]
:local dd    [:pick $cdate 8 10]
:local identitydate "$[identity get name]_$yyyy-$MM-$dd"

:local fileup "$identitydate-dynamicdata"

/ip/cloud print file=cloud
/ip/dhcp-server/lease print file=leases
/interface/bridge/host print file=hosts
/interface/wireless/registration-table print file=registrations

:local cloudcontents [/file get cloud.txt contents]
:local leasescontents [/file get leases.txt contents]
:local hostscontents [/file get hosts.txt contents]
:local registrationscontents [/file get registrations.txt contents]

:local fileupcontents "$cloudcontents . $leasescontents . $hostscontents . $registrationscontents"

/file print file="$fileup" 
/file set $fileup contents=$fileupcontents

/tool fetch upload=yes mode=ftp ascii=no src-path="/$fileup" dst-path="/mikrotik-backups/$fileup" address=192.168.2.22 port=21 user=mikrotik password=mikrotik

/file remove [find name=$fileup]

/file remove "$fileup"
 
User avatar
rextended
Forum Guru
Forum Guru
Posts: 12014
Joined: Tue Feb 25, 2014 12:49 pm
Location: Italy
Contact:

Re: Frustrated trying to create a script

Sat Sep 30, 2023 3:27 am

The first error is not specify the RouterOS version.
The second, if one file is > 4KB, nothing is returned.
The third, if the fileupcontents size is > 4KB, the file is not written.
Last edited by rextended on Sat Sep 30, 2023 3:33 am, edited 1 time in total.
 
Josephny
Member
Member
Topic Author
Posts: 495
Joined: Tue Sep 20, 2022 12:11 am

Re: Frustrated trying to create a script

Sat Sep 30, 2023 3:33 am

RouterOS 7.12beta3

I don’t think any of the initial files are greater than 4KB. But, I don’t understand what “nothing is returned” means.
 
User avatar
rextended
Forum Guru
Forum Guru
Posts: 12014
Joined: Tue Feb 25, 2014 12:49 pm
Location: Italy
Contact:

Re: Frustrated trying to create a script

Sat Sep 30, 2023 3:38 am

Also if on device name is present one forbidden characters on remote filesystem, the file is not created.

I don’t think any of the initial files are greater than 4KB.
Is easy that you go over 4K...

simplified v7.10+ code

/system
:local identitydate "$[identity get name]_$[clock get date]"

/file remove [find where name=tmpresults.txt]
:delay 1s
:execute "/ip cloud pri; :put \"\\r\\n\";  /ip dhcp-server lease pri det; :put \"\\r\\n\"; /int bridge host pri det; :put \"\\r\\n\"; /int wireless reg pri det" file=tmpresults.txt
:delay 2s

/tool fetch upload=yes mode=ftp ascii=no src-path=tmpresults.txt dst-path="/mikrotik-backups/$identitydate-dynamicdata" address=192.168.2.22 port=21 user=mikrotik password=mikrotik

/file remove [find where name=tmpresults.txt]
 
Josephny
Member
Member
Topic Author
Posts: 495
Joined: Tue Sep 20, 2022 12:11 am

Re: Frustrated trying to create a script

Sat Sep 30, 2023 10:27 am

Wow!

That is really beautiful code.

I am hoping to deploy this script across multiple devices, including hex, rb5009, hAPac and hAPax.

So, the wifiwave2 devices I inserted:
/int wireless reg pri det
to look like this:
:execute "/ip cloud pri; :put \"\\r\\n\";  /ip dhcp-server lease pri det; :put \"\\r\\n\"; /int bridge host pri det; :put \"\\r\\n\"; /int wireless reg pri det; :put \"\\r\\n\";/int wif reg pri det" file=tmpresults.txt
The code above is executed until the part where it results in a 'command not found' error.

For example, on an ax3 (wifiwave2), the code stops at:
/int wireless reg pri det
On a hEX, it stops, but I'm not missing any data because the hEX has neither /int wireless nor /int wifiwave2

Is there a way to get it ignore the error?

Thank you very much.
 
User avatar
rextended
Forum Guru
Forum Guru
Posts: 12014
Joined: Tue Feb 25, 2014 12:49 pm
Location: Italy
Contact:

Re: Frustrated trying to create a script

Sat Sep 30, 2023 1:04 pm

You must adapt the script for detect if on the device where is executed is installed (or not) the wifiwave2 package...

example code

:local identitydate "$[/sys identity get name]_$[clock get date]"
:local stringexec   "/sys identity print; :put \"\\r\\n\"; /ip cloud pri; :put \"\\r\\n\";  /ip dhcp-server lease pri det; :put \"\\r\\n\"; /int bridge host pri det"

:if ([:len [/int find where ( (type="wlan") or (type="wifi") )]] > 0) do={
    :if ([:len [/sys package find where name="wifiwave2"]] = 1) do={
        :set stringexec "$stringexec; :put \"\\r\\n\"; /int wifiwave2 reg pri det"
    } else={
        :set stringexec "$stringexec; :put \"\\r\\n\"; /int wireless reg pri det"
    }
}

/file remove [find where name=tmpresults.txt]
:delay 1s
:execute $stringexec file=tmpresults.txt
:delay 2s

/tool fetch upload=yes mode=ftp ascii=no address=192.168.2.22 port=21 user=mikrotik password=mikrotik \
    src-path=tmpresults.txt dst-path="/mikrotik-backups/$identitydate-dynamicdata.txt"

/file remove [find where name=tmpresults.txt]
Last edited by rextended on Mon Oct 02, 2023 11:53 am, edited 8 times in total.
 
Josephny
Member
Member
Topic Author
Posts: 495
Joined: Tue Sep 20, 2022 12:11 am

Re: Frustrated trying to create a script

Sat Sep 30, 2023 4:19 pm

Truly brilliant.

And very kind of you to do this.

Thank you.

Now to figure out how to make all this data useful....
 
Josephny
Member
Member
Topic Author
Posts: 495
Joined: Tue Sep 20, 2022 12:11 am

Re: Frustrated trying to create a script

Sat Sep 30, 2023 6:54 pm

I made a couple of small changes (that actually work, but I'm sure there's a more efficient way):

Added another IF for devices with no wireless interfaces
Added .txt so Windows isn't confused
Added system identity to beginning of saved file (to avoid having to look at the file name to know which device's data I'm looking at)
/system
:local identitydate "$[identity get name]_$[clock get date]"
:local stringexec   "/system iden print; :put \"\\r\\n\"; /ip cloud pri; :put \"\\r\\n\";  /ip dhcp-server lease pri det; :put \"\\r\\n\"; /int bridge host pri det"

:if ([:len [/system package find where name="wifiwave2"]] > 1) do={
    :set stringexec "$stringexec; :put \"\\r\\n\" /int wifiwave2 reg pri det"
} 

:if ([:len [/system package find where name="wifiwave2"]] > 1) do={
    :set stringexec "$stringexec; :put \"\\r\\n\" /int wireless reg pri det"
}


/file remove [find where name=tmpresults.txt]
:delay 1s
:execute $stringexec file=tmpresults.txt
:delay 2s

/tool fetch upload=yes mode=ftp ascii=no address=192.168.2.22 port=21 user=mikrotik password=mikrotik \
    src-path=tmpresults.txt dst-path="/mikrotik-backups/$identitydate-dynamicdata.txt"

/file remove [find where name=tmpresults.txt]
 
User avatar
rextended
Forum Guru
Forum Guru
Posts: 12014
Joined: Tue Feb 25, 2014 12:49 pm
Location: Italy
Contact:

Re: Frustrated trying to create a script

Mon Oct 02, 2023 11:37 am

the double identical "if" instead of "if/else" make no sense...

Altered the previous post for reflect the changes you want.
 
Josephny
Member
Member
Topic Author
Posts: 495
Joined: Tue Sep 20, 2022 12:11 am

Re: Frustrated trying to create a script

Mon Oct 02, 2023 3:30 pm

I actually tried to make it work with if-else, but failed.

Then I thought that maybe there might be a possibility of both packages being installed, in which case the repeated if would be successful.

Regardless, thank you again.

Now I'm playing with the get command to try to do this in a way that produces better formatted results (for importing into something easy to view).

If only The Dude provided this info, I'd be set.

Who is online

Users browsing this forum: noyo and 5 guests