Comparing integers: arithmetic expression or conditional expression

76,362

Solution 1

Yes, we have two different ways of comparing two integers.

It seems that these facts are not widely accepted in this forum:

  1. Inside the idiom [ ] the operators for arithmetic comparison are -eq, -ne, -lt, -le, -gt and -ge.

    As they also are inside a test command and inside a [[ ]].

    Yes inside this idioms, =, <, etc. are string operators.

  2. Inside the idiom (( )) the operators for arithmetic comparison are ==, !=, <, <=, >, and >=.

    No, this is not an "Arithmetic expansion" (which start with a $) as $(( )). It is defined as a "Compound Command" in man bash.

    Yes, it follows the same rules (internally) of the "Arithmetic expansion" but has no output, only an exit value. It could be used like this:

if (( 2 > 1 )); then ...

Why do we have two different ways for comparing two integers?

I guess that the latter (( )) was developed as a simpler way to perform arithmetic tests. It is almost the same as the $(( )) but just has no output.

Why two? Well the same as why we have two printf (external and builtin) or four test (external test, builtin test, [ and [[). That's the way that the shells grow, improving some area in one year, improving some other the next year.

When to use which?

That's a very tough question because there should be no effective difference. Of course there are some differences in the way a [ ] work and a (( )) work internally, but: which is better to compare two integers? Any one!.

When comparing two integers, can these two methods always be used interchangeably?

For two numbers I am compelled to say yes.
But for variables, expansions, mathematical operations there may be key differences that should favor one or the other. I can not say that absolutely both are equal. For one, the (( )) could perform several math operations in sequence:

if (( a=1, b=2, c=a+b*b )); then echo "$c"; fi

If yes, why does Bash have two methods rather than one?

If both are helpful, why not?.

Solution 2

Historically, the test command existed first (at least as far back to Unix Seventh Edition in 1979). It used the operators = and != to compare strings, and -eq, -ne, -lt, etc. to compare numbers. For example, test 0 = 00 is false, but test 0 -eq 00 is true. I don't know why this syntax was chosen, but it may have been to avoid using < and >, which the shell would have parsed as redirection operators. The test command got another syntax a few years later: [ … ] is equivalent to test ….

The [[ … ]] conditional syntax, inside which < and > can be used as operators without quoting, was added later, in ksh. It kept backward compatibility with [ … ], so it used the same operators, but added < and > to compare strings (for example, [[ 9 > 10 ]] but [[ 9 -lt 10 ]]). For more information, see using single or double bracket - bash

Arithmetic expressions also came later than the test command, in the Korn shell, at some time in the 1980s. They followed the syntax of the C language, which was very popular in Unix circles. Thus they used C's operators: == for equality, <= for less-or-equal, etc.

Unix Seventh Edition didn't have arithmetic expressions, but it did have the expr command, which also implemented a C-like syntax for integer operations, including its comparison operators. In a shell script, the characters < and > had to be quoted to protect them from the shell, e.g. if expr 1 \< 2; … is equivalent to if test 1 -lt 2; …. The addition of arithmetic expressions to the shell made most uses of expr obsolete, so it isn't well-known today.

In an sh script, you'd generally use arithmetic expressions to calculate an integer value, and [ … ] to compare integers.

if [ "$((x + y))" -lt "$z" ]; then …

In a ksh, bash or zsh script, you can use ((…)) for both.

if ((x + y < z)); then …

The [[ … ]] form is useful if you want to use conditionals involving things other than integers.

Solution 3

According to the test man page, = and != are used for string comparisons while the expressions -eq, -gt, -lt, -ge, -le, and -ne are integer comparisons. I've always followed this convention when writing shell scripts and it always works. Be aware that if you have variables in the expression, you may need to quote the variables in some way to avoid doing a null comparison.

On paper, we do string/number comparisons without much thought. A computer on the other hand doesn't know if 987 is a number or a string of characters. You need the different operators to tell the computer what to do so you get the right result. There is some additional info here that explains some of the history. Essentially, the variables are untyped and have remained that way for historical compatibility.

Share:
76,362

Related videos on Youtube

Tim
Author by

Tim

Elitists are oppressive, anti-intellectual, ultra-conservative, and cancerous to the society, environment, and humanity. Please help make Stack Exchange a better place. Expose elite supremacy, elitist brutality, and moderation injustice to https://stackoverflow.com/contact (complicit community managers), in comments, to meta, outside Stack Exchange, and by legal actions. Push back and don't let them normalize their behaviors. Changes always happen from the bottom up. Thank you very much! Just a curious self learner. Almost always upvote replies. Thanks for enlightenment! Meanwhile, Corruption and abuses have been rampantly coming from elitists. Supportive comments have been removed and attacks are kept to control the direction of discourse. Outright vicious comments have been removed only to conceal atrocities. Systematic discrimination has been made into policies. Countless users have been harassed, persecuted, and suffocated. Q&amp;A sites are for everyone to learn and grow, not for elitists to indulge abusive oppression, and cover up for each other. https://softwareengineering.stackexchange.com/posts/419086/revisions https://math.meta.stackexchange.com/q/32539/ (https://i.stack.imgur.com/4knYh.png) and https://math.meta.stackexchange.com/q/32548/ (https://i.stack.imgur.com/9gaZ2.png) https://meta.stackexchange.com/posts/353417/timeline (The moderators defended continuous harassment comments showing no reading and understanding of my post) https://cs.stackexchange.com/posts/125651/timeline (a PLT academic had trouble with the books I am reading and disparaged my self learning posts, and a moderator with long abusive history added more insults.) https://stackoverflow.com/posts/61679659/revisions (homework libels) Much more that have happened.

Updated on September 18, 2022

Comments

  • Tim
    Tim almost 2 years

    In Bash, two integers can be compared using conditional expression

    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.

    or arithmetic expression:

    <= >= < > comparison

    == != equality and inequality

    Why do we have two different ways for comparing two integers? When to use which?

    For example, [[ 3 -lt 2 ]] uses conditional expression, and (( 3 < 2 )) uses arithmetic expression. Both returns 0 when the comparison is true

    When comparing two integers, can these two methods always be used interchangeably? If yes, why does Bash have two methods rather than one?

    • dave_thompson_085
      dave_thompson_085 about 8 years
      = != < <= > >= compare strings. 1 -eq 01 but 1 != 01 and 8 -lt 42 but 8 > 42
    • Tim
      Tim about 8 years
      They are overloaded in arithmetic expressions.
    • Angel Todorov
      Angel Todorov about 8 years
      you'll have to search in the bash changelogs to find out when each feature was added. I suspect the arithmetic expressions was added much later than the test command.
    • Tim
      Tim about 8 years
      I am not asking about comparing strings. @muru.
  • Tim
    Tim about 8 years
    In my post, = and != are arithmetic operators, while the manpage of test only shows conditional expression operators.
  • ceving
    ceving almost 6 years
    = is an assignment and == is a comparison in arithmetic expansions. The question quotes it correctly. But the answer is wrong.
  • Roland
    Roland over 4 years
    Also ( is not a reserved word in bash so there is no need to put spaces around ((, as opposed to [ or [[