首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >如果-eq与[[ . ]]中的非数字参数一起使用,如何使bash抛出错误?

如果-eq与[[ . ]]中的非数字参数一起使用,如何使bash抛出错误?
EN

Stack Overflow用户
提问于 2020-11-19 10:31:54
回答 2查看 377关注 0票数 0

我最近写了一个相当复杂的bash脚本,在测试期间我注意到了一个错误行为。在分析过程中,我发现有一个错误,在条件命令中我意外地使用了-eq而不是==,也就是说,我有一个类似的

代码语言:javascript
复制
[[ "$var1" -eq "$var2" ]] || { ... }

而不是

代码语言:javascript
复制
[[ "$var1" == "$var2" ]] || { ... }

因为在本例中,var1var2可能包含任意字符串,而不仅仅是整数,所以在那个地方发生了可怕的错误。在命令行进行快速调查使问题更加清楚:

代码语言:javascript
复制
root@cerberus:~/scripts# [[ '0' -eq '0' ]] && echo Equal
Equal
root@cerberus:~/scripts# [[ '0' -eq '1' ]] && echo Equal
root@cerberus:~/scripts# [[ 'A' -eq 'B' ]] && echo Equal
Equal

最后一行对我来说很令人惊讶。从巴什手册 (在页面的末尾,强调我的意思):

arg1 OP arg2 OP是‘-eq’、‘-ne’、‘- is’、‘-le’、‘-gt’或‘-ge’之一。如果arg1分别等于、不等于、小于、小于或等于、大于或等于arg2,则这些算术二进制运算符返回true。Arg1和arg2可以是正整数,也可以是负整数。与[[命令、Arg1和Arg2 ]一起使用时被计算为算术表达式(参见Shell算术).

由于上面的代码中的最后一行使用-eq[[命令,因此根据上面的引文将'A''B'计算为算术表达式。令我惊讶的是,这并没有造成bash抛出错误,因为显然没有合理的方法将'A''B'转换为整数。

然后,我试图找出bash在计算算术表达式时应用的规则。手册中的各章描述了一些边缘情况(例如表达式的展开是nullunset),但是对于一个表达式的展开是一个不能算术计算的任意字符串的情况,它没有任何规定。注意:我知道我们不应该使用仅链接的引用,但是相应的部分太长了,不能被引用。

出于好奇,我试图找出像'A'这样的算术值的实际计算值。这比预期的要困难得多,因为bash实际上拒绝对字符串进行“正常”算术扩展,即使可以对这些字符串进行算术计算:

代码语言:javascript
复制
root@cerberus:~/scripts# echo $(( 0 ))
0
root@cerberus:~/scripts# echo $(( '0' ))
-bash: '0' : syntax error: operand expected (error token is "'0' ")
root@cerberus:~/scripts# echo $(( 'A' ))
-bash: 'A' : syntax error: operand expected (error token is "'A' ")

由于我想要解决这个问题,而不是症状,所以我放弃了尝试找出bash在算术计算任意字符串时应用的规则,或者为什么它在算术扩展时抛出错误,而不是在与[[一起进行算术计算时抛出错误。

相反,我现在想知道bash中是否有一个选项使它在中抛出一个错误--在任何情况下,它必须对表达式进行算术计算,但这是不可能的,因为该表达式不是算术表达式。如果没有这样的选项,我想知道,在-eq-ne (等等)的参数在[[ ]]中使用时,这些参数的算术计算是否有可能做到这一点。

EN

回答 2

Stack Overflow用户

回答已采纳

发布于 2020-11-19 13:39:48

-eq[[ ... ]]中将其操作数计算为算术表达式,即它们在((...))中的行为类似。有或没有美元符号的变量都会展开,但如果它们的展开是有效的标识符,则该名称的变量用于生成要比较的值。

代码语言:javascript
复制
#!/bin/bash
A=foo
B=bar
for foo in 0 1 ; do
    for bar in 0 1 ; do
        if [[ A -eq B ]] ; then
            echo "$A ($foo) eq $B ($bar)"
        else
            echo "$A ($foo) ne $B ($bar)"
        fi
    done
done

这种扩展是递归发生的。

代码语言:javascript
复制
#!/bin/bash
a=1 b=a c=b d=c e=d f=e g=f h=g i=h j=i k=j l=k m=l
n=m o=n p=o q=p r=q s=r t=s u=t v=u w=v x=w y=x z=y
[[ z -eq 1 ]] && echo ok

递归限制为1024:

代码语言:javascript
复制
#!/bin/bash
(
    echo -n a=
    for var in {a..z}{a..z}{a..z} ; do
        echo $var
        echo -n $var=
    done
    echo 42
    echo '[[ a -eq 42 ]] && echo ok'
) | bash
票数 1
EN

Stack Overflow用户

发布于 2020-11-19 13:15:13

如果您使用[ ... ]而不是[[ ... ]],我认为您将得到您想要的行为。鉴于以下职能:

代码语言:javascript
复制
check_equal() {
  if [ "$var1" -eq "$var2" ]; then
    echo equal
  else
    echo not equal
  fi
}

这些工作如预期的那样:

代码语言:javascript
复制
$ var1=0 var2=0 check_equal
equal
$ var1=0 var2=1 check_equal
not equal

但是,传递非数值参数会导致错误消息:

代码语言:javascript
复制
$ var1=A var2=0 check_equal
testnumbers.sh: line 2: [: A: integer expression expected
not equal

当然,这里的缺点是您使用的是[ ... ]表达式,它在某些方面比bash专用的[[ ... ]]表达式更脆弱。

票数 1
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/64909825

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档