Shell:如果a小于b,“a -lt b”是不是真的?

时间:2012-02-19 00:56:40

标签: linux shell

我没有接受过Linux培训,但我可以通过一些文档查找来解决问题,但我很难过。

我找到了一个脚本,可以帮助我在dd wrt路由器启动时设置日期,但前提是当前日期小于存储日期。如果你愿意,我可以分享整个脚本,但是归结为这个声明在我预期的时候没有评估为真。我将文字放入,而不是变量,它仍然不返回true,它执行“else”语句:

 if [ 021715402012 -lt 021815402012 ]
  then
     echo "the first seems less than the second"
  else
     echo "the first does not seem less than the second for some reason"
  fi

我希望“第一个似乎不到第二个”,但事实并非如此...... 这是溢出问题吗?我试着把它变成这样的字符串比较:

if [ x021715402012 -lt x021815402012 ]

并尝试将其放在引号中:

if [ "x021715402012" -lt "x021815402012" ]

它总是执行else。如果a小于b,“a -lt b”是不是真的?

任何对此的见解都会受到赞赏,我很难过!

4 个答案:

答案 0 :(得分:3)

-lt等助记符可以说是来自20世纪50年代后期.LT.等原始Fortran比较器。

是的,在shell中,-lt执行'小于'数字比较。 (请注意,在Perl中,数字比较为<等,字符串比较由字母运算符表示,例如-lt!)

然而,在一些(可能是很多)shell中,转换和比较可以用本地长整数格式完成。如果您使用的是32位计算机,则引用的值超过32位(带符号)范围10倍左右。在64位计算机上,或者使用long long的shell,你会没事的。

十进制数的十六进制等值为021715402012 = 0x50E56BD1C和021815402012 = 0x5144C9E1C;因为8,它们不能是八进制的。(但是,如果shell确实将前导零解释为'八进制',那么第二个数字只是021或17十进制,因为8结束了八进制数。但是,64-我测试的位shell(Mac OS X 10.7.3和RHEL 5)似乎都将它们视为十进制,而不是八进制。)

下面的示例代码,在64位下编译,给出以下输出:

021715402012 =  240565532 = 0x050E56BD1C
021815402012 =  340565532 = 0x05144C9E1C

在32位下编译,它提供以下输出:

021715402012 = 2147483647 = 0x007FFFFFFF
021815402012 = 2147483647 = 0x007FFFFFFF

如果这是你的shell中发生的事情,那么将解释-lt的结果行为。您可以通过测试这两个值是否为-eq来确认;反直觉地说,在使用32位shell将其算术限制为long(32位)有符号整数的假设下,这可能会评估为真。

#include <stdio.h>
#include <stdlib.h>

int main(void)
{
    char *array[] = { "021715402012", "021815402012" };
    for (int i = 0; i < 2; i++)
    {
        int j = atoi(array[i]);
        long k = strtol(array[i], 0, 10);
        printf("%-10s = %10d = 0x%.10lX\n", array[i], j, k);
    }
    return 0;
}

答案 1 :(得分:1)

您使用的是什么外壳和版本?某处有嵌入式控制角色的机会吗? (尝试删除重新键入代码。)在openSUSE 11.2(x86_64)上:

$if [ 021715402012 -lt 021815402012 ]; then echo yes; else echo no; fi
yes

有趣的是,

$if [ 012 -lt 11 ]; then echo yes; else echo no; fi
no

这让我感到惊讶,因为man bash表示-lt执行算术比较,而带前导0的常量被解释为八进制。所以我希望这能测试10是否小于11,因为012 base 8 = 8 + 2。

有人可以让我们直截了当吗?

答案 2 :(得分:1)

正在发生一些事情......

您的shell似乎使用了32位算术,并且您的数字溢出了格式。

此外,shell脚本中的所有命令参数都是字符串,因此除非参数中的字符对shell解析器有意义,否则引号将完全没有效果。

shell if语句实际上正在运行the test(1) command,它作为简写链接到[。 (然后它忽略了最后的]。)虽然命令可以使用相同的运算符进行数字和字符串比较,但是当命令设计时,运算符采用某种类型,{ {1}}假设为数字。

关于bash和ash(破折号)我在 x ... 示例中收到错误消息。

答案 3 :(得分:0)

我不确定你的特定shell是否正在使用这种解释,但这就是我认为正在发生的事情:

021715402012是一个11位八进制数。 021815402012是一个两位数的八进制数,以非八进制数字(8)结尾。

021715402012021,显然第二个更小。

关于您的其他尝试,test[命令的文档表明-lt仅对数字参数有效,而不是字符串。