bug-bash
[Top][All Lists]
Advanced

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

Re: behavior of arithmetic evaluation operator inside extended test oper


From: Inian Vasanth
Subject: Re: behavior of arithmetic evaluation operator inside extended test operator
Date: Tue, 19 May 2020 23:04:34 +0530

Thanks Greg for the explanation. Yes your explanation  aligns with my
understanding too.

My recommendation was to check if this behavior needs to be documented as a
side-note in this section of
http://www.gnu.org/savannah-checkouts/gnu/bash/manual/bash.html#Bash-Conditional-Expressions
to
explain that, any other primaries other than the ones mentioned above will
be evaluated as a literal string result. I also tried finding an
explanation in your wiki at
https://mywiki.wooledge.org/BashGuide/TestsAndConditionals, but there
wasn't an explicit point made.

On Tue, May 19, 2020 at 7:40 PM Greg Wooledge <wooledg@eeg.ccf.org> wrote:

> On Tue, May 19, 2020 at 06:10:30PM +0530, Inian Vasanth wrote:
> > The behavior of arithmetic context operator $((..)) inside [[..]] is not
> so
> > well defined.
>
> It's simply a substitution.  The $(( )) is evaluated, and the result
> is placed into the [[ ]] command as a word.
>
> > The downside is the operator
> > without $ when used as ((..)) just behaves as double grouping,
>
> Correct, as you demonstrated below.
>
> > but $((..))
> > behaves as a valid arithmetic evaluation followed by non empty string
> > comparison `-n`
>
> Well, yes.  What did you *expect*?  What are you trying to do?
>
> > bash -cx '[[ (( 100 < 3 )) ]] && echo ok'
> > + bash -cx '[[ (( 100 < 3 )) ]] && echo ok'
> > + [[ 100 < 3 ]]
> > + echo ok
>
> The parentheses here are doubly redundant.  You're performing a grouping,
> but there is only one operator, so there's nothing to group *for*.  And
> you're doing the grouping twice, for no discernable reason.
>
> You're also using the < operator in a [[ ]] command, which is string
> comparison, not integer comparison.
>
> If your goal was simply "check whether the integer 100 is less than the
> integer 3", you don't need to use the [[ ]] command at all.
>
> if ((100 < 3)); then
>   echo ok
> else
>   echo not ok
> fi
>
> If you insist on using [[ ]] for some reason, integer comparisons can be
> forced with the -lt -gt (et al.) operators.
>
> if [[ 100 -lt 3 ]]; then
> ...
>
> > bash -cx '[[ $(( 100 < 3 )) ]] && echo ok'
> > + bash -cx '[[ $(( 100 < 3 )) ]] && echo ok'
> > + [[ -n 0 ]]
> > + echo ok
> > ok
>
> Here, you are forcing an arithmetic substitution to be explicitly
> performed,
> before the [[ ]] command begins.  The result of the arithmetic substitution
> is a word, and that word will be checked for non-zero-length by the [[
> command.  It is exactly as if you had written:
>
> tmp=$((100 < 3))
> [[ $tmp ]] && ...
>
> The form [[ $x ]] is just the same as [[ -n $x ]] and that's what you
> have written here.
>
>
> > bash -cx '[[ $(( 100 < 300 )) ]] && echo ok'
> > + bash -cx '[[ $(( 100 < 300 )) ]] && echo ok'
> > + [[ -n 1 ]]
> > + echo ok
> > ok
>
> Same.  It doesn't matter whether the result of the arithmetic expression
> is 1 (true) or 0 (false), because both of these words are strings of
> non-zero length.
>
> To repeat: if your goal is to compare integers, you should use one of
> these forms:
>
> if ((x < y)); then ...
>
> if [[ $x -lt $y ]]; then ...
>
> if test "$x" -lt "$y"; then ...
>
> if [ "$x" -lt "$y" ]; then ...
>
>
> Remember, the [ and [[ commands are just that: *commands*.  They are not
> a part of the "if" syntax.  You don't *need* them every time you use
> an "if".  You don't need to bend over backwards trying to work out how
> to merge the command you actually want to use, together with the [[
> command.
>
> Just omit the [[ if it's not the command you want.
>


-- 
Regards,
INIAN VASANTH P


reply via email to

[Prev in Thread] Current Thread [Next in Thread]