1

In bash manual, Section 6.5 Shell Arithmetic says

<= >= < > comparison
== != equality and inequality 

&& logical AND
|| logical OR

Their meanings seem to imply they are used for conditional expressions. But they appear in the section for arithmetic expressions.

  1. So can they be used in conditional expressions?

    In Section 6.4, we already have operators for conditional expressions, which are similar to <=,>=,<,>,==,!= for arithmetic expressions:

    arg1 OP arg2

    OP is one of ‘-eq’, ‘-ne’, ‘-lt’, ‘-le’, ‘-gt’, or ‘-ge’. These arithmetic binary operators return true if arg1 is equal to, not equal to, less than, less than or equal to, greater than, or greater than or equal to arg2, respectively. Arg1 and arg2 may be positive or negative integers.

    We also already have operators for conditional expressions, which are similar to && and || for arithmetic expressions:

    • -a and -o for test i.e. [...]
    • && and || for [[...]].

    Since we have the operators introduced for conditional expressions, why do we need those similar operators introduced for arithmetic expressions?

  2. Can they be used in test commands?

    We know that if is followed by a test command

    The syntax of the if command is:

    if test-commands; then
    consequent-commands;
    [elif more-test-commands; then
    more-consequents;]
    [else alternate-consequents;]
    fi
    

    [...] and [[...]] both take conditional expressions within and create test commands. Can they take arithmetic expressions?

    What makes me even confused is when [...] and [[...]] with arithmetic expressions in them are used as test command, [...] behaves incorrectly, while [[...]] correctly:

    $ if [ 1 > 2 ]; then echo h; else echo b; fi
    h
    $ if [ 1 < 2 ]; then echo h; else echo b; fi
    h
    $ if [[ 1 < 2 ]]; then echo h; else echo b; fi
    h
    $ if [[ 1 > 2 ]]; then echo h; else echo b; fi
    b
    
  • 1
    See: help test – Cyrus Mar 18 '16 at 5:47
7

It's very simple. You just have to understand [], [[]] and (()) as completely different beasts.

[ expression ] is just an invocation of a program [ (just a different name for test) and takes the expression as arguments, just like for all command calls in bash. That means, you must use whitespace between arguments, especially after [ and before ], and keywords and special characters have to be escaped or quoted, and variables are expanded in the usual way.

Within the expression, -gt, -lt and related are used for numerical comparison, while >, < and the sort, are for string comparisons. Think of [ as nothing to do with bash, just calling a command that evaluates expressions and returns 0 (true) or non-zero (false), as all programs do.

Boolean operators && and || can't be used in there, because they get interpreted by bash and not passed to test as arguments. -a and -o are used instead. But you can always do [ test1 ] && [ test2 ] || [ test3 ], which are 3 test invocations, combined by bash's usual boolean operators (that is, if first fails, the second is skipped).

Note that bash still comes with its own implementation of [ (builtin), but that doesn't change the way it's treated syntactically.

[[ ]] and (( )) are not builtin replacements for commands, but parts of a special syntax, so different rules apply. See man page for details on how variable names are wildcards are treated there. Boolean operators && and || have the usual meaning.

The [[ ]] one is string-centered: all comparsions are for strings (but are more "modern", locale-aware than in [, although test could be platform-dependent). It handles also file tests, regex and so on.

The (( )) is for arithmetic expressions. Variable names don't require $ there, and you can mostly just write mathematical expressions in there - that of course includes comparisons (which are numerical). Comparisons in this case are no different from any other arithmetic expression, true is 1, false is 0, and you can write stuff like (( x=y*(z>4) )). If used in a conditional expression, nonzero is true and zero is false. You can also capture the result as $(( )).

So:

  • [[ ]] string conditionals, pattern matching and file tests
  • (( )) arithmetic expressions and conditionals
  • [ ] test command: handles both, special nonstandard syntax for boolean operators and comparison operators
0

A "conditional expression" is what is used inside the test [ or [[ command.

So, both your questions 1 and 2 mean the same:

  1. can they be used in conditional expressions?: Yes.
  2. can they be used in test commands?: Yes.

However, they do not mean what you think:

$ if [[ 1 < 2 ]]; then echo yes; else echo no; fi
yes
$ if [[ 10 < 2 ]]; then echo yes; else echo no; fi
yes
$ if [[ e < è ]]; then echo yes; else echo no; fi
yes

That comparison, as the manual states:

True if string1 sorts before string2 lexicographically.

That is: in dictionary order (and affected by the LC_COLLATE variable)

The test with a simple [ will redirect output to files:

$ if [ e < è ]; then echo h; else echo b; fi
bash: è: No such file or directory
b

To get it to work, you need to use a backslash (quote the < and >):

$ if [ e \< è ]; then echo h; else echo b; fi
h

But I do not recommend using < in test.


In the other place where <, <=, >, >= may be used are inside arithmetic tests, which may be part of an if test:

$ if (( 12 <= 15 )); then echo "yes"; fi
yes

Which, yes, is equivalent to:

$ if [[ 12 -le 15 ]]; then echo "yes"; fi
yes

And quite similar to:

$ if [ 12 -le 15 ]; then echo "yes"; fi
yes

So, yes, all this:

<= >= < >     comparison
== !=         equality and inequality 
&&            logical AND
||            logical OR

Are used for conditional expressions inside Arithmetic Expressions:

$ if (( ( ((2<3)&&(3>7)) * 18 ) == 0 )); then echo "yes"; fi
yes

Which are not the same conditional expressions as inside the test command.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.