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: Greg Wooledge
Subject: Re: behavior of arithmetic evaluation operator inside extended test operator
Date: Tue, 19 May 2020 10:10:33 -0400
User-agent: Mutt/1.10.1 (2018-07-13)

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.



reply via email to

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