Page 1 of 1

the irrationality of [find]

Posted: Wed Oct 02, 2024 9:52 am
by Wheelhousemarine
Hello,
Today I noticed an inconsistency of [find] in the script:
When I try to reset counter of "a" user in hotspot, I use:
/ip hotspot user reset-counters [find name="a"];
Everything was perfect until I removed "a".
According to common thinking, my command line above will look for "a" to reset the counter, if it can't find "a", it won't do anything. But surprisingly, when it can't find "a", it reseted all other users as if to vent its anger. It's so hard for other users, just because a doesn't exist, they are affected by a command that has nothing to do with them. Is this a ROS7 bug?

Re: the irrationality of [find]

Posted: Wed Oct 02, 2024 9:55 am
by Amm0
No. [find] mean "all". It's a filter, so if you don't apply any filters like name="a" to match, the default is return all. Otherwise, the would be no way to express "find everything".

You can test find by using it standalone:
:put [/ip hotspot user find name=a]
*29
:put [/ip hotspot user find]
*0;*2;*3;...

And the numbers from "find" are the same as "/ip hotspot user print show-id" or "/ip hotspot user print show-id where name=a". So you can use the "where <filters>" clause to test, and the use that in a "/ip/hotspot/user reset-counters [find <filters>]". FWIW, in a print statement, "where" is same as "find" - but it named where since it a clause in the expression, not a standalone command requiring [].

It's powerful, but not easy at first.

Re: the irrationality of [find]

Posted: Wed Oct 02, 2024 10:30 am
by msatter
Amm0
Otherwise, the would be no way to express "find everything".
you can find all by using a Regex.
/user> :put [find name~"."] 
*1;*2;*4;*6;*9
/user> :put [find]         
*1;*2;*4;*6;*9
So there was no need to have find only "find" selection being that powerful. It is a shortcut as it is implemented now, it has it's pitfalls.

General information:
/user> :put [find name~"a"] 
*1;*2
/user> :put [find name="a"]

The line with ~ in it will find any names with an "a" in it and the the one with = in it, needs an exact match. The second line does so not find any names.

Re: the irrationality of [find]

Posted: Wed Oct 02, 2024 10:39 am
by infabo
What Wheelhousemarine really wanted to report is, translated to commands:
/ip hotspot user reset-counters [find name="a"];
/ip hotspot user remove a;
/ip hotspot user reset-counters [find name="a"]; -> resets counters of ->ALL<- users

Re: the irrationality of [find]

Posted: Wed Oct 02, 2024 11:17 am
by Amm0
Now I get it. I ain't arguing this is great. But it's rational.

/ip/hotspot/user/reset-counters has some trickier logic... here "numbers=" attribute is optional. And numbers= is actual name of attribute used by the unnamed arg used by [find name=a]. So "reset-counter" already assumes all, if numbers= is not provided. And since numbers= cannot be set to an empty list, it's ignored.

Why it doesn't happen elsewhere... is normally when you a find in something like /ip/address/set [find comment="xxx"]... and the find results in 0 match... the "set" will FAIL, since it requires a some .id/numbers= to set.

Not saying this correct or ideal. But since "reset-counters" will work without any .id's (i.e. numbers= is optional), that why a "failed find" actually does NOT block it since numbers=/.ids are optional.

Re: the irrationality of [find]

Posted: Wed Oct 02, 2024 11:30 am
by jaclaz
So it is not a quirk of the find command in itsellf, but rather a "wrong implied default" of "all" in the command /ip hotspot user reset-counters?

How can it be worked around?
Like checking if "numbers" is defined and only run the command if the condition is true?

Re: the irrationality of [find]

Posted: Wed Oct 02, 2024 11:40 am
by Amm0
So it is not a quirk of the find command in itsellf, but rather a "wrong implied default" of "all" in the command /ip hotspot user reset-counters?
That's what I'm suggesting: it's the command's logic, not find's logic at issue. A zero-length list is NOT nil/[:nothing], so reset-counter should treat an empty list as just "nothing to reset", not ignore it because it's an empty list...
:put [:typeof [/ip hotspot user find name=a]]                      
# array
:put [:len [/ip hotspot user find name=a]]      
# 0
You can of course check the list with [:len] before calling reset-counter, and be okay for schedule script...but checking the list be a PITA at the CLI.

Welcome to file an issue and see with Mikrotik says. I cannot find the post, but I think this one has come up before...

Re: the irrationality of [find]

Posted: Wed Oct 02, 2024 4:00 pm
by Wheelhousemarine
the one with = in it, needs an exact match. The second line does so not find any names.
yes, and do you know and why does the statement affect all users when the condition [find name=a] returns that no user satisfies. I think this is very error prone.

Re: the irrationality of [find]

Posted: Wed Oct 02, 2024 4:04 pm
by Wheelhousemarine
No. [find] mean "all". It's a filter, so if you don't apply any filters like name="a" to match, the default is return all. Otherwise, the would be no way to express "find everything".

You can test find by using it standalone:
:put [/ip hotspot user find name=a]
*29
:put [/ip hotspot user find]
*0;*2;*3;...
[find] mean all, ok, no problem, but why [find name=a] still mean all if "a" removed?

Re: the irrationality of [find]

Posted: Wed Oct 02, 2024 4:08 pm
by Wheelhousemarine
So it is not a quirk of the find command in itsellf, but rather a "wrong implied default" of "all" in the command /ip hotspot user reset-counters?

How can it be worked around?
Like checking if "numbers" is defined and only run the command if the condition is true?
yes, there are many ways to fix this "bug", I just brought up an irrationality of the [find] condition.

Re: the irrationality of [find]

Posted: Wed Oct 02, 2024 4:38 pm
by jaclaz
yes, there are many ways to fix this "bug", I just brought up an irrationality of the [find] condition.
But that [find name="a"] works just fine, as it finds nothing and returns nothing.

The issue is in the command:
/ip hotspot user reset-counters
that works for "all" even if no parameters are passed to it.

Re: the irrationality of [find]

Posted: Thu Oct 03, 2024 4:13 am
by Larsa
Yeah, and as a workaround, you’ll need to use for example a foreach loop. Something like this:

/ip hotspot user
:foreach user in=[find name~"^adam"] do={
reset-counters $user
another-command $user
etc…
}

Re: the irrationality of [find]

Posted: Thu Oct 03, 2024 5:53 am
by Wheelhousemarine
yes, there are many ways to fix this "bug", I just brought up an irrationality of the [find] condition.
But that [find name="a"] works just fine, as it finds nothing and returns nothing.
No, if it find nothing, it return all. surprise?
[/quote]

The issue is in the command:
/ip hotspot user reset-counters
that works for "all" even if no parameters are passed to it.
[/quote]
No, i am not user command /ip hotspot user reset-counters; i used: /ip hotport user reset-counters [find name = "a"]; but it still works for all in case "a" is removed.

Re: the irrationality of [find]

Posted: Thu Oct 03, 2024 11:37 am
by jaclaz
No, i am not user command /ip hotspot user reset-counters; i used: /ip hotport user reset-counters [find name = "a"]; but it still works for all in case "a" is removed.
Exactly. :)

You use the command:
/ip hotspot user reset-counters [find name = "a"]
BUT the find command cannot find that particular user, and returns an empty value, so the command becomes:
/ip hotspot user reset-counters <nothing>
which is actually:
/ip hotspot user reset-counters

The problem is in the command, that shouldn't do anything if issued without any argument, and to delete all users there would be the need for a special parameter *like*:
/ip hotspot user reset-counters all

Re: the irrationality of [find]

Posted: Thu Oct 03, 2024 4:17 pm
by Wheelhousemarine
No, i am not user command /ip hotspot user reset-counters; i used: /ip hotport user reset-counters [find name = "a"]; but it still works for all in case "a" is removed.
Exactly. :)

You use the command:
/ip hotspot user reset-counters [find name = "a"]
BUT the find command cannot find that particular user, and returns an empty value, so the command becomes:
/ip hotspot user reset-counters <nothing>
which is actually:
/ip hotspot user reset-counters

The problem is in the command, that shouldn't do anything if issued without any argument, and to delete all users there would be the need for a special parameter *like*:
/ip hotspot user reset-counters all
thanks, i understand how it works.
just, i'm not comfortable with do-something-for<nothing> = do-something-for<all>

Re: the irrationality of [find]

Posted: Thu Oct 03, 2024 5:54 pm
by Amm0
Oh you should file a bug report. The "reset-counters" should handle the case there is a find & it's nothing.

Just because it's explainable, does mean it makes sense. :?

Re: the irrationality of [find]

Posted: Thu Oct 03, 2024 6:33 pm
by Larsa
I totally agree. Everything should be handled consistently and users shouldn't have to know all the little exceptions that could lead to serious issues. At the very least, the documentation should have clear warnings about these risks.

Re: the irrationality of [find]

Posted: Thu Oct 03, 2024 9:38 pm
by Amm0
I totally agree. Everything should be handled consistently and users shouldn't have to know all the little exceptions that could lead to serious issues. At the very least, the documentation should have clear warnings about these risks.
Basically anything that appears on the right-side "Actions" in the new Winbox4 is going to be trickier in CLI...since these "special verbs" all deviate from standard list/items with get/set/find/print/enable/disable scheme in some ways. It's these verbs where the CLI dragons live.

I think Mikrotik does not always get reports about some of these, since folks move on to the next thing... is part of the problem. And, even if they did, might miss the issues. e.g. without @infabo's explanation above, it sounded more like a complaint about [:find]:
/ip hotspot user reset-counters [find name="a"];
/ip hotspot user remove a;
/ip hotspot user reset-counters [find name="a"]; -> resets counters of ->ALL<- users

Re: the irrationality of [find]

Posted: Thu Oct 03, 2024 10:25 pm
by msatter
Thinking differently and avoiding so unwanted results:

Preferred way to do this and I found this in an other topic viewtopic.php?t=211390:
:foreach r in=[find name="test"] do={reset-counters $r; :put "Counters zeroed"}

Older remarks:
:local username "test"; :if [find name=$username] do {reset-counters [find name=$username]; :put "Counters zeroed for user: $username"} else {:put "Warning: User $username not found!"}
And then, why are we using find, when the default search field is "name"?

User test exists:
/ip/hotspot/user> reset-counters test 
/ip/hotspot/user> reset-counters fa  
no such item
/ip/hotspot/user> :do {reset-counter fa; :put "counters zeroed."} on-error={:put "Not found"}
Not found
/ip/hotspot/user> :do {reset-counter test; :put "counters zeroed."} on-error={:put "Not found"}
counters zeroed.
Then RouterOS is correctly working when the selector is name. However if you want to use a different selector then you need to use find. Which does produce unwanted results when there is no match.