Check whether one number equals another number in bash

后端 未结 4 1802
庸人自扰
庸人自扰 2020-12-24 07:02

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 prog

4条回答
  •  一向
    一向 (楼主)
    2020-12-24 07:38

    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 suppose 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
    

    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 issues is why does 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, run sub-commands) before it actually execute 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.

提交回复
热议问题