50

我一直在尝试比较 Bash 中的两个数字是否相等(如果相等则打印一条消息),但是对于这个简单的程序,我收到了一些奇怪的错误消息:

#!/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

相应的错误显示在导致这些错误的行下方。

4

5 回答 5

80

一定是:

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

如果您更喜欢可读性更强且不言自明的代码,请使用以下语法:

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

说明

要比较整数,您必须使用这些运算符(从 复制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

运算符 == 和 != 仅用于字符串比较。

有关信息:“[”命令是系统“test”命令的别名。

于 2013-04-07T21:13:03.750 回答
5

Shell 脚本并不是真正意义上的完整语言,它在很大程度上依赖于其他外部命令才能工作。

变量使用它们前面的符号。$许多 shell 脚本语言使用变量符号来帮助区分字符串和变量。

例如:

foo=foo_value
echo foo foo $foo foo

将打印:

foo foo foo_value foo

请注意,字符串的echo语句不需要引号。Windows Batch shell 非常相似:

set foo = foo_value
echo foo foo %foo% foo

如您所见,当应该扩展变量时使用符号,而不是在定义它时使用那是因为 Unix shell 是智能 shell。他们甚至在执行命令行之前就对它进行了修改。shell 将在执行替换环境变量:

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

这将打印出:

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

如果您使用该set -xv命令,您会看到它在执行之前$foo="whose value is this"被扩展为。bar=whose value is this"

在像KornShell和 Bash 这样的Bourne 风格的 shell中,if声明并不是你想象的那样。该if命令执行该语句,如果该命令返回零值,将选择if 子句。例如:

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

请注意,if 子句不是布尔语句。这是一个实际执行的命令。

在 Unix 开发早期的某个地方,test创建了该命令。你可以做一个man 测试,看看如何使用它。

test命令允许您执行此操作:

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

如果你这样做:

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

您将看到[实际存在一个名为的命令,并且是该test命令的硬链接。创建它是为了使if语句看起来更像是您将在常规编程语言中看到的if语句:

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

它与上面的脚本完全相同,但使用[而不是test.

这解释了为什么在许多测试中需要破折号test(它是命令的参数,参数以破折号开头!)。它还解释了为什么在[and周围需要空格]。这些是实际的 Unix 命令,Unix 命令周围必须有空格,以便 shell 可以处理它们。

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.

于 2013-04-07T22:07:32.943 回答
4

对于第一条错误消息,删除美元符号$,等号周围不允许有空格=

x=3

对于第二条错误消息,在前面插入一个空格和一个美元符号,$在后面插入一个x空格3

if [ $x -eq 3 ]

正如loentar 正确指出的那样,它一定是-eq并且既不是=也不是==

于 2013-04-07T21:09:34.867 回答
3
  • 空格在[ ]表达式中是强制性的,所以

    if [ $x == 3 ]; then

  • 你需要一个关于测试中变量的标记[ ]

于 2013-04-07T21:08:11.253 回答
1

For clarity, use == for equality rather than = even though both work. The former encourages the use of [[ and the latter can be confused with an assignment. Use (( … )) or -lt and -gt for numerical comparison.

if [[ "${my_var}" == "val" ]]; then
  do_something
fi

if (( my_var == 3 )); then
  do_something
fi

if [[ "${my_var}" -gt 3 ]]; then
  do_something
fi
于 2021-05-19T21:01:29.377 回答