Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Check whether one number equals another number in Bash

Tags:

bash

I've been trying to compare whether two numbers in Bash are equal (and print a message if they are equal), but I'm getting some strange error messages for this simple program:

#!/bin/bash  fun2 (){     $x = 3     //#prog.sh: line 4: =: command not found     if [x == 3]         then     //#prog.sh: line 6: [x: command not found             echo "It's 3!"     fi } fun2 

The corresponding errors are shown below the lines that caused those errors.

like image 935
Anderson Green Avatar asked Apr 07 '13 21:04

Anderson Green


2 Answers

It must be:

 if [ $x -eq 3 ]; then ..... 

If you prefer a more readable and self-explanatory code, use this syntax:

 if test $x -eq 3; then ..... 

Explanation:

To compare integers you must use those operators (copied from man test):

   INTEGER1 -eq INTEGER2           INTEGER1 is equal to INTEGER2     INTEGER1 -ge INTEGER2           INTEGER1 is greater than or equal to INTEGER2     INTEGER1 -gt INTEGER2           INTEGER1 is greater than INTEGER2     INTEGER1 -le INTEGER2           INTEGER1 is less than or equal to INTEGER2     INTEGER1 -lt INTEGER2           INTEGER1 is less than INTEGER2     INTEGER1 -ne INTEGER2           INTEGER1 is not equal to INTEGER2 

operators == and != are for string comparison only.

For information: "[" command is an alias for system "test" command.

like image 90
loentar Avatar answered Sep 24 '22 02:09

loentar


Shell scripting wasn't really meant to be a full language, and it is heavily dependent upon other external commands to work.

Variables use a sigil which is that $ in front of them. A lot of shell scripting languages use variable sigils to help distinguish between a string and a variable.

For example:

foo=foo_value echo foo foo $foo foo 

Will print:

foo foo foo_value foo 

Note that quotes are not necessary for the echo statement for strings. Windows Batch shell is very similar:

set foo = foo_value echo foo foo %foo% foo 

As you can see, the sigil is used when the variable is supposed to be expanded, but not when you define it. That's because Unix shells are intelligent shells. They munge the command line before it is even executed. The shell will substitute the environment variables before execution:

foo=bar $foo="whose value is this"  # Note the dollar sign! echo The value of foo is $foo echo The value of bar is $bar 

This will print out:

The value of foo is foo The value of bar is whose value is this 

If you use the set -xv command, you'll see that $foo="whose value is this" is expanded to bar=whose value is this" before it is executed.

In Bourne style shells like KornShell and Bash, the if statement isn't what you think it is. The if command executes the statement, and will select the if clause if that command returns a zero value. For example:

cat "foo" > my_file       # Create a one line file with the string foo in it. if grep -q "foo" my_file  # grep command will return a zero exit code if it finds foo then     echo "The string 'foo' is in file my_file" fi 

Notice that the if clause isn't a Boolean statement. It's an actual command that is executed.

Somewhere early in Unix development, the test command was created. You can do a man test and see how to use it.

The test command allows you to do this:

foo=3 bar=3 if test foo -eq bar then     echo "foo and bar are equal" else     echo "foo and bar are not equal" fi 

If you do this:

$ ls -li /bin/test /bin/[ 

You will see that a command called [ actually exists, and is a hard link to the test command. This was created to make an if statement look more like a if statement you'll see in regular programming languages:

foo=3 bar=3 if [ foo -eq bar ] then     echo "foo and bar are equal" else     echo "foo and bar are not equal" fi 

It is the exact same script as above, but with [ instead of test.

This explains why you need the dash in many tests (it's a parameter to the test command, and parameters start with a dash!). It also explains why you need spaces around the [ and ]. These are actual Unix commands, and Unix commands must have white spaces around them, so the shell can process them.

Another issue is: Why does the shell have two different sets of tests for strings and numbers? That's because strings may contain nothing but digits, but are not really numeric. For example, if you do inventory, you might have a part number 001 and 01. Numerically, they're equal, but as strings, they're two different strings. There is no way for the shell script to know. Instead, you must let the shell script know if it's a numeric comparison or a string comparison.

Perl has similar issues since you don't declare variables as numeric or non-numeric:

                         Shell Script              Perl Boolean Operator     Numeric     String     Numeric    String ===================  =======     ======     =======    ====== Equals                 -eq        =           ==         eq Not Equals             -ne        !=          !=         ne Greater Than           -gt        >           >          gt Less Than              -lt        <           <          lt Greater or Equals      -ge        >=          >=         ge Less Than or Equals    -le        <=          <=         le 

You can try a few other things:

$ echo "*"    # Echos the asterisk $ echo *      # No quotes: Prints all files in current directory 

Notice again the shell expands the * before executing the echo command. This is the main difference between a shell script and a typical programming language. The shell first does expansion (fill in environment variables, glob substitution, and run sub-commands) before it actually executes the command.

The set -xv will show you what command is being executed, and how the shell expands the command before executing. Doing set +xv will shut that off. Play around with that, and you'll soon understand the shell a bit better.

like image 26
David W. Avatar answered Sep 24 '22 02:09

David W.