Community discussions

MikroTik App
 
vasilaos
Member Candidate
Member Candidate
Topic Author
Posts: 120
Joined: Tue Aug 04, 2009 9:50 am

elif statement

Wed Oct 08, 2014 11:52 am

can i use elif statement in mirkotik scripts?
 
User avatar
Deantwo
Member
Member
Posts: 331
Joined: Tue Sep 30, 2014 4:07 pm

Re: elif statement

Wed Oct 08, 2014 3:49 pm

Not according to the wiki at least.
http://wiki.mikrotik.com/wiki/Manual:Sc ... _statement

Putting another IF statement inside the ELSE statement seems to be the only way.

No ELSE IF and no SWITCH CASE, it sure makes the scripts look more messy.
Last edited by Deantwo on Wed Oct 08, 2014 4:04 pm, edited 1 time in total.
 
User avatar
mrz
MikroTik Support
MikroTik Support
Posts: 7042
Joined: Wed Feb 07, 2007 12:45 pm
Location: Latvia
Contact:

Re: elif statement

Wed Oct 08, 2014 3:52 pm

else if and switch case are not implemented at the moment
 
User avatar
Jotne
Forum Guru
Forum Guru
Posts: 3291
Joined: Sat Dec 24, 2016 11:17 am
Location: Magrathean

Re: elif statement

Fri Sep 06, 2019 8:03 am

else if and switch case are not implemented at the moment
So you are working on it? I am waiting with high expectation :)
 
User avatar
SiB
Forum Guru
Forum Guru
Posts: 1888
Joined: Sun Jan 06, 2013 11:19 pm
Location: Poland

Re: elif statement

Fri Sep 06, 2019 10:31 am

WorkARound, mutch better then if else if else....
local myFunc do={put $1}
if ($n=1) do={$MyFunc "A"}
if ($n=2) do={$MyFunc "B"}
if ($n=3) do={$MyFunc "C"}
if ($n!=1 & $n!=2 & $n!=3) do={$MyFunc "Other"}
 
alna7ari
just joined
Posts: 2
Joined: Wed Nov 10, 2021 1:15 am

Re: elif statement

Wed Nov 10, 2021 1:32 am

Late, but I will leave the answer to others because I did not find any convincing answer
:global counter 0
:global ifElseWorkAround do={
  #if
  if ($counter > 180) do={
    #your code
    :set counter ($counter+1)
    :return null;
  } 
  #elseif
  if ($counter > 90) do={
    #your code
    :set counter ($counter+2)
    :return null;
  }
  #elseif
  if ($counter > 45) do={
    #your code
    :set counter ($counter+3)
    :return null;
  }
  # Repeat the elseif code as many as you want
  # Finally, put the code that you want to execute if none of the above conditions are met
  # else code here
  :set counter ($counter+4)
};
$ifElseWorkAround;
 
User avatar
Deantwo
Member
Member
Posts: 331
Joined: Tue Sep 30, 2014 4:07 pm

Re: elif statement

Fri Nov 12, 2021 11:33 am

WorkARound, mutch better then if else if else....
...
&
Late, but I will leave the answer to others because I did not find any convincing answer
...
I am sorry you two, but how and why would either of those two code samples work as an ELSE IF?
Sure you can maybe make a nicer looking SWITCH CASE looking IF list, but that still isn't the same and totally requires you to know exactly what you are doing.

There is no pretty workaround. Best you can do is this:
if ($b1) do={
    # if $b1 then this
} else={
    if ($b2) do={
        # else if $b2 then this
    } else={
        # else then this
    }
}
You can't make your flow control look pretty if it makes your code way more likely to fail.
 
User avatar
rextended
Forum Guru
Forum Guru
Posts: 11982
Joined: Tue Feb 25, 2014 12:49 pm
Location: Italy
Contact:

Re: elif statement

Fri Nov 12, 2021 12:06 pm

The better is a @SiB variant, because you can change, or is changed, the tested value.
Like "elseif" or switch are executed only one instance.

(SiB errors fixed, is valid code, introduced other, fixed on 2023)
:global n 2
{
    :local MyFunc do={ :put $1; :set n 0 }
    :local MyFuncU do={ :put "Out of range (1-3) values for N ($1)"; :set n 0 }
    :local switch true
    :if ($n=1 and $switch) do={ [$MyFunc "A"]; :set switch false }
    :if ($n=2 and $switch) do={ [$MyFunc "B"]; :set switch false }
    :if ($n=3 and $switch) do={ [$MyFunc "C"]; :set switch false }
    :if ($switch) do={ [$MyFuncU $n] }
}
EDIT: fidex syntax errors not noticed before.
Last edited by rextended on Sun Feb 26, 2023 4:50 pm, edited 3 times in total.
 
User avatar
Deantwo
Member
Member
Posts: 331
Joined: Tue Sep 30, 2014 4:07 pm

Re: elif statement

Fri Nov 12, 2021 3:19 pm

The better is a @SiB variant, because you can change, or is changed, the tested value.
Like "elseif" or switch are executed only one instance.
...
I guess your change there fixes the issue I had about if $n is equal to multiple cases at the same time. But it still feels like you are making a basic IF ELSEIF ELSE more complicated than it has to be.

Your average user won't be able to just copy-paste your code example and make it work without possibly making something wrong.

Keep It Simple Stupid (KISS) is important if you want your code to be maintainable by others. And giving complicated workarounds to inexperienced people here seems like a bad idea too.
 
User avatar
rextended
Forum Guru
Forum Guru
Posts: 11982
Joined: Tue Feb 25, 2014 12:49 pm
Location: Italy
Contact:

Re: elif statement

Fri Nov 12, 2021 3:44 pm

I guess your change there fixes the issue I had about if $n is equal to multiple cases at the same time.
Both Yes, good deduction, and also No:
It simply act on this way, like compared only one time, because the value can change for various reason somewhere else.

something like this can help:
[...]
:local switch true
:local temporary-variable-that-store-the-value-readed-only-one-time $n
:if ($temporary-variable-that-store-the-value-readed-only-one-time=1 && switch) do={ $MyFunc "A"; :set $switch false }
[...]

This is only a workaround because elseif / switch / case / etc. do not exist for now...
 
fragtion
Member Candidate
Member Candidate
Posts: 257
Joined: Fri Nov 13, 2009 10:08 pm
Location: Johannesburg, South Africa

Re: elif statement

Sun Feb 26, 2023 3:04 pm

The better is a @SiB variant, because you can change, or is changed, the tested value.
Like "elseif" or switch are executed only one instance.

(SiB errors fixed, is valid code)
:global n 2
{
    :local MyFunc do={ :put $1; :set $n 0 }
    :local MyFuncU do={ :put "Out of range (1-3) values for N ($1)"; :set $n 0 }

    :local switch true
    :if ($n=1 && switch) do={ $MyFunc "A"; :set $switch false }
    :if ($n=2 && switch) do={ $MyFunc "B"; :set $switch false }
    :if ($n=3 && switch) do={ $MyFunc "C"; :set $switch false }
    :if (switch) do={ $MyFuncU $n }
}

@rextended: forgive me for any ignorance on my part, but shouldn't it be "&& $switch" rather than "&& switch" ? what am I missing? 😄

I'm trying to make a script to automatically QoS LTE speeds when primary cell tower goes offline and my speeds drop from ~ 50Mbps, all the way down to 1-2Mbps and I need to do the best I can with that small bandwidth... here's where I'm at:
/system scheduler add interval=3s name=wan1-autoqos on-event="/system/script/run wan1-autoqos" policy=ftp,reboot,read,write,policy,test,password,sniff,sensitive,romon start-time=startup
/system/script/ name=wan1-autoqos :
:local spdmin 512
:local spdmax 51200
:local spdsafe 2500
:local pingcount 3
:local movingaverage 2

:global wan1qos
:global avgpacketloss
:local curpacketloss
:local adjamt 0
:local spdadj
:local lastqos $wan1qos

#:log info ("")

:if ([/interface/ethernet/get ether1_wan running]=true) do={
  :local count [/ping address="8.8.4.4" interface="ether1_wan" src-address="192.168.8.100" size=28 interval=1 count=$pingcount]
  #:local count 3
  :set curpacketloss (($pingcount - $count) * 100 / $pingcount)
  #:log info "Percent of pings lost: $curpacketloss% (received $count / $pingcount)"
  :set avgpacketloss (($avgpacketloss * ($movingaverage - 1) + $curpacketloss) / $movingaverage)
  #:log info "Avgpacketloss: $avgpacketloss"
  :local switch true
  :if (($avgpacketloss > 10) && ($curpacketloss > $avgpacketloss)) do={
    # Packet loss - Decrease speeds
    :if ($wan1qos > 5000 && switch) do= { :set wan1qos $spdsafe; set $switch false }
    :if ($wan1qos > 4000 && switch) do= { :set adjamt 512; :set $switch false }
    :if ($wan1qos > 3000 && switch) do= { :set adjamt 128; :set $switch false }
    :if ($wan1qos > 0 && switch) do= { :set adjamt 64; :set $switch false }
    :set spdadj (-1 * $adjamt)
  } else {
    # No packet loss or packet loss decreasing - Increase speed
    :if ($wan1qos > 5000 && $wan1qos != $spdmax && switch) do= { :set wan1qos $spdmax; set $switch false }
    :if ($wan1qos > 4000 && switch) do= { :set adjamt 512; :set $switch false }
    :if ($wan1qos > 3000 && switch) do= { :set adjamt 128; :set $switch false }
    :if ($wan1qos > 0 && switch) do= { :set adjamt 64; :set $switch false }
    :set spdadj (1 * $adjamt)
  }
  :set wan1qos ($wan1qos + $spdadj)
  :if ($wan1qos < $spdmin) do={ :set wan1qos $spdmin }
  :if ($wan1qos > $spdmax) do={ :set wan1qos $spdmax }
  :if ($wan1qos != $lastqos) do= {
    /system/script/run qos-env
    :log info "QoS: $wan1qos (Adjust: $spdadj)"
  }
}
/system/script/ name=qos-env :
:global wan1qos
:local qosrate $wan1qos
/queue/tree/set "WAN_COMBINED" max-limit=($qosrate . "k")
/queue/tree/set "1. VOIP" max-limit=($qosrate . "k") limit-at=(((32 * $qosrate) / 1000) . "k")
/queue/tree/set "2. DNS" max-limit=($qosrate . "k") limit-at=(((16 * $qosrate) / 1000) . "k")
/queue/tree/set "3. ICMP" max-limit=($qosrate . "k") limit-at=(((16 * $qosrate) / 1000) . "k")
/queue/tree/set "4. ACK" max-limit=($qosrate . "k") limit-at=(((256 * $qosrate) / 1000) . "k")
/queue/tree/set "5. UDP" max-limit=($qosrate . "k") limit-at=(((256 * $qosrate) / 1000) . "k")
/queue/tree/set "6. QUIC" max-limit=($qosrate . "k") limit-at=(((256 * $qosrate) / 1000) . "k")
/queue/tree/set "7. HTTP" max-limit=($qosrate . "k") limit-at=(((512 * $qosrate) / 1000) . "k")
/queue/tree/set "8. OTHER" max-limit=($qosrate . "k") limit-at=(((512 * $qosrate) / 1000) . "k")
/queue/tree/set "9. HTTP_BIG" max-limit=($qosrate . "k") limit-at=(((128 * $qosrate) / 1000) . "k")
/queue/tree/set "10. TORRENTS" max-limit=($qosrate . "k") limit-at=(((64 * $qosrate) / 1000) . "k")

The script pair will make adjustments to the qos limits depending on ongoing packet loss. If the limit is already low, the adjustments will be smaller, and if the rate is higher, the adjustments are more aggressive, of course

Besides for clarity on "switch / $switch", any improvements to the script in general are certainly welcome :D
 
User avatar
rextended
Forum Guru
Forum Guru
Posts: 11982
Joined: Tue Feb 25, 2014 12:49 pm
Location: Italy
Contact:

Re: elif statement

Sun Feb 26, 2023 4:52 pm

@rextended: forgive me for any ignorance on my part, but shouldn't it be "&& $switch" rather than "&& switch" ? what am I missing? 😄
Fixed the script: I add some parts but do not fix or check syntax errors.
The code is only for a concept, but now is really working code.

*************************


Fixed all syntax errors and reformatted, check the differencies.
Some errors: "else {" is wrong, is "else={"
"do= {" is wrong, is "do={"
etc.
I do not check the logic or if the script do what expected, i check only errors for make the code work.

revised code

:local spdmin    512
:local spdsafe  2500
:local spdmax  51200

:local iface     "ether1_wan"
:local srcadd    192.168.8.100
:local pingcount 3
:local pingadd   8.8.4.4

:global avgpacketloss
:global wan1qos
:local lastqos       $wan1qos
:local movingaverage 2
:local curpacketloss ""
:local adjamt        0
:local spdadj        ""

:if ([/interface ethernet get $iface running]) do={
    :local count [/ping address=$pingadd interface=$iface src-address=$srcadd size=28 interval=1 count=$pingcount]
#    :local count 3
    :set curpacketloss ((($pingcount - $count) * 100) / $pingcount)
#    :log info "Percent of pings lost: $curpacketloss% (received $count / $pingcount)"
    :set avgpacketloss ((($avgpacketloss * ($movingaverage - 1)) + $curpacketloss) / $movingaverage)
#    :log info "Avgpacketloss: $avgpacketloss"
    :local switch true
    :if (($avgpacketloss > 10) and ($curpacketloss > $avgpacketloss)) do={
        # Packet loss - Decrease speeds
        :if (($wan1qos > 5000) and $switch) do={ :set wan1qos $spdsafe; \
                                                                  :set switch false }
        :if (($wan1qos > 4000) and $switch) do={ :set adjamt 512; :set switch false }
        :if (($wan1qos > 3000) and $switch) do={ :set adjamt 128; :set switch false }
        :if (($wan1qos >    0) and $switch) do={ :set adjamt  64; :set switch false }
        :set spdadj ($adjamt * -1)
    } else={
        # No packet loss or packet loss decreasing - Increase speed
        :if (($wan1qos > 5000) and $switch and ($wan1qos != $spdmax)) do={:set wan1qos $spdmax; \
                                                                  :set switch false }
        :if (($wan1qos > 4000) and $switch) do={ :set adjamt 512; :set switch false }
        :if (($wan1qos > 3000) and $switch) do={ :set adjamt 128; :set switch false }
        :if (($wan1qos >    0) and $switch) do={ :set adjamt  64; :set switch false }
        :set spdadj ($adjamt * 1)
    }
    :set wan1qos ($wan1qos + $spdadj)
    :if ($wan1qos < $spdmin) do={ :set wan1qos $spdmin }
    :if ($wan1qos > $spdmax) do={ :set wan1qos $spdmax }
    :if ($wan1qos != $lastqos) do= {
        /system script run "qos-env"
        :log info "QoS: $wan1qos (Adjust: $spdadj)"
    }
}

revised code

:global wan1qos
:local qosrate $wan1qos
:local qosratek ($qosrate * 1024)
/queue tree 
set "WAN_COMBINED" max-limit=$qosratek
set  "1. VOIP"     max-limit=$qosratek limit-at=($qosrate *  32)
set  "2. DNS"      max-limit=$qosratek limit-at=($qosrate *  16)
set  "3. ICMP"     max-limit=$qosratek limit-at=($qosrate *  16)
set  "4. ACK"      max-limit=$qosratek limit-at=($qosrate * 256)
set  "5. UDP"      max-limit=$qosratek limit-at=($qosrate * 256)
set  "6. QUIC"     max-limit=$qosratek limit-at=($qosrate * 256)
set  "7. HTTP"     max-limit=$qosratek limit-at=($qosrate * 512)
set  "8. OTHER"    max-limit=$qosratek limit-at=($qosrate * 512)
set  "9. HTTP_BIG" max-limit=$qosratek limit-at=($qosrate * 128)
set "10. TORRENTS" max-limit=$qosratek limit-at=($qosrate *  64)
 
fragtion
Member Candidate
Member Candidate
Posts: 257
Joined: Fri Nov 13, 2009 10:08 pm
Location: Johannesburg, South Africa

Re: elif statement

Sun Feb 26, 2023 6:50 pm

@rextended: forgive me for any ignorance on my part, but shouldn't it be "&& $switch" rather than "&& switch" ? what am I missing? 😄
Fixed the script: I add some parts but do not fix or check syntax errors.
The code is only for a concept, but now is really working code.

*************************


Fixed all syntax errors and reformatted, check the differencies.
Oh wow, that's looking brilliant!! Simply amazing work, I'll try it and advise any feedback 😁😁 THANK YOU for taking the time to go over this script and help jazz it up like this👏🏻 Sorry for hijacking this thread with the script (I was also just trying to find the best way to do "elseif") we can move this to a new thread if necessary.

The original script wasn't tested much yet and I'm already thinking of a few improvements. For example, if the speed is throttled, but usage is low (nobody browsing at that moment), it could tend to release the throttle too quickly with 3s intervals so maybe then it's better to increase the moving average to more counts, but we can play with these values as a starting point and see what works best
It also spams the logs considerably when all the queues are changed, and I'm worried all changes to the config are being written to nand every 3 seconds? XD not sure if this is the case, or a concern at all

Who is online

Users browsing this forum: No registered users and 19 guests