将变量作为字符串或整数进行比较时,有什么主要区别


22

出于好奇,在进行bash变量比较(其值为an integer)时,可以对照声明为an int或as的一些预定义值对其进行测试string

示例脚本

#!/bin/bash
f1()
{
        [ "$1" == "1" ] && echo "$FUNCNAME: \"1\" compared as string"
}

f2()
{
        [[ "$1" -eq 1 ]] && echo "$FUNCNAME: \"1\" compared as int"
}

f1 $1
f2 $1

输出

$  ./param.sh 1
f1: "1" compared as string
f2: "1" compared as int

$  ./param.sh blah
$

两个函数的行为方式相同,所以我想知道在检查整数变量时是否存在首选方法?我会进行检查intint因为它比较严格,但是我想知道是否有任何缺点string吗?

在这种情况下,f2()对比较也要严格一些,即,传递一个十进制值会破坏它,而f1()没有问题。


请注意,Bash确实没有Integer数据类型。您基本上可以暗示Bash将String视为整数。
helpermethod 2014年

Answers:


18

是的,有很多差异。例如,=检查精确的字符串相等性,但-eq在检查相等性之前对两个表达式进行算术运算:

$ [ " 1 " -eq 1 ] && echo equal || echo not
equal
$ [ " 1 " = 1 ] && echo equal || echo not
not

$ [ +1 -eq 1 ] && echo equal || echo not
equal
$ [ +1 = 1 ] && echo equal || echo not
not

$ [ "0+1" -eq 1 ] && echo equal || echo not
equal
$ [ "0+1" = 1 ] && echo equal || echo not
not

同样,空字符串恰好在数值上等于零:

$ [ "" -eq 0 ] && echo equal || echo not
equal
$ [ "" = 0 ] && echo equal || echo not
not

而整个其他类的差异,当你把比较运营商出现-考虑<VS -lt,例如:

$ [[ 2 -lt 10 ]] && echo less || echo not
less
$ [[ 2 < 10 ]] && echo less || echo not
not

这是因为字符串“ 2”按字母顺序在字符串“ 10”之后(因为1在2之前),但是数字“ 2”在数字上小于数字“ 10”。


2
别忘了还有(( ... ))数字运算。(( " 1 " == 1 )) && echo yes || echo no结果yes
帕特里克

7

当比较大于或小于以下值时,整数与字符串比较将变得最重要:

#!/bin/bash

eleven=11
nine=9

[[ $nine < $eleven ]] && echo string   # fail

[[ "$nine" -lt "$eleven" ]] && echo integer # pass

第一个失败,因为按字典顺序排序时9在11之后。

请注意,使用引号不会确定要比较字符串还是数字,运算符会确定。您可以添加或删除上面的引号,这没有任何区别。Bash在双括号内捕获了未定义的变量,因此不需要使用引号。由于在数字测试中使用带单引号的引号不会节省您的时间:

[ "" -lt 11 ]

无论如何都是错误(“需要整数表达式”)。引号是在单括号中进行字符串比较的有效保护措施:

[ "" \< 11 ]

注意内括号,""-eq 0但不是== 0


1
在bash中,并不一定要在双括号中引用变量:内置[[函数足够聪明,可以记住变量在哪里,并且不会被空变量欺骗。单括号([)没有此功能,需要加引号。
glenn jackman 2014年

@glennjackman没注意到。[[ -lt 11 ]]是一个错误,但nothing=; [[ $nothing -lt 11 ]]不是。我对最后一段做了一些修改。
goldilocks 2014年

2

除了刚才所说的。
用数字比较相等性更快,尽管在shell脚本中很少需要快速计算。

$ b=234
$ time for ((a=1;a<1000000;a++)); do [[ $b = "234" ]]; done

real    0m13.008s
user    0m12.677s
sys 0m0.312s

$ time for ((a=1;a<1000000;a++)); do [[ $b -eq 234 ]]; done

real    0m10.266s
user    0m9.657s
sys 0m0.572s

考虑到它们做不同的事情,我想说性能是无关紧要的-您需要使用执行所需功能的工具。
godlygeek

@godlygeek变量的相等比较可以双向实现。“ -eq”更快。
伊曼纽尔2014年

他们测试不同的平等定义。如果您想回答“此变量是否保留确切的字符串123”这个问题,则只能使用=,因为using -eq也将匹配“ +123”。如果您想知道“此变量是否作为算术表达式评估时,比较等于123”,则只能使用-eq。我唯一能看到程序员不在乎使用哪个相等定义的地方是当他知道变量的内容提前被约束为特定模式时。
godlygeek

@godlygeek有趣,问题是关于比较数字的相等性,就好像它们是字符串一样,是否适合于将变量提前约束为特定模式的情况?
伊曼纽尔

您的示例(b=234)符合该模式-因为您自己分配了它,所以它不是+234或“ 234”或“ 233 + 1”,因此您知道将它作为字符串和数字进行比较是同等有效的。但是OP的脚本由于将输入作为命令行参数,因此没有该约束-考虑将其称为./param.sh 0+1or./param.sh " 1"
godlygeek 2014年
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.