2012-02-19 123 views
6

我没有接受过Linux培训,但是我可以通过一些doc查找来搞清楚,但是我很难过。壳牌:如果a小于b,“a -lt b”是不是真的?

我发现了一个脚本,它可以帮助在启动时在我的dd wrt路由器上设置日期,但只有当前日期小于存储日期。如果你愿意的话,我可以分享整个剧本,但是当我期望的时候,这个叙述不会被评估为真实。我把文本中,而不是变量,它仍然没有返回true,则执行了“其他”的语句:

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" ] 

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

任何洞察到这一点将不胜感激,我很难过!

+0

在Mac上的'bash'中正常工作。 – kindall 2012-02-19 01:27:36

+1

嗯,当我测试你的例子时,它会打印出“第一个看起来不到第二个”。这是什么bash或sh版本?如果你想了解更多关于-lt等的信息,你可以查看'help test','help'或'man test'。 – 2012-02-19 01:28:40

+0

也适用于我的openwrt路由器。但我显然有不同的实现,因为我的“坏数字”包含了“x”。 – 2012-02-19 01:49:47

回答

3

助记符如-lt可能来自原始的Fortran比较器,例如从20世纪50年代末起的.LT.

是的,在shell中,-lt做了一个小于'的数字比较。 (但请注意,在Perl中,数字比较是<等,字符串比较用字母运算符表示,如-lt!)

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

十六进制数等于十六进制数为021715402012 = 0x50E56BD1C和021815402012 = 0x5144C9E1C;它们不能是八进制的,因为8(但是,如果shell将前导零解释为'八进制',那么第二个数字只是021或17十进制,因为8结束了八进制数,但是,位弹我测试上(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位外壳将其算术限制为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; 
} 
+0

谢谢@Jonathan如此彻底的回应。我认为问题是溢出情况,它们都很大。我在每个结尾都删除了2012年,并且按照预期开始行动,即使是领先零。所以八进制比较理论在这里并不是这样。由于这些数字实际上是以奇怪的字符顺序排列的日期(mmddHHMMyyyy),所以我会拆分比较来比较年份,然后再比较mmddHHMM,我相信这会解决这个问题。再次感谢! – 2012-02-19 02:46:40

1

你使用的是什么shell和版本?任何嵌入式控制角色的机会? (尝试删除重新键入代码。)在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一致的常量被解释为八进制。所以我期望这个测试十是否小于十一,因为012 base 8 = 8 + 2.

有人可以设置我们吗?

+0

有趣的发现那里。 – hochl 2012-02-19 01:43:39

+0

你的外壳不是解释八进制....也许是布莱恩的。 – 2012-02-19 01:46:13

+1

我得到了“不”。问题出在@Jonathan上面说过的 - 数字太大,所以我认为,解释是一样的。我通过将-lt改为-gt来证实了这一点。它仍然说“不”,如果不是gt并且不是lt,必须相等,然后......在小路由器的眼中。 – 2012-02-19 02:51:20

0

我不知道,如果你的特殊外壳也使用这种解释,但在这里就是我认为正在发生的事情:

021715402012是一个11位数字的八进制数。 021815402012是一个由非八进制数字(8)终止的两位八进制数。

021715402012021,显然第二个更小。

关于你提到的其他尝试,为test[命令的文件表明,-lt仅适用于数字参数,而不是字符串。

+0

有趣的假说;酸性测试是降低前导零。 'x'版本会比较相等,不会,因为两个字符串评估为零数字。 – 2012-02-19 01:46:56

+0

@JonathanLeffler:可能。让我看看,如果我的openwrt框可以重现原来的行为....实际上,我用前导零得到“预期”行为,而用'x'我得到“灰色:x021715402012:坏数字”。 – 2012-02-19 01:49:00

1

有几件事情正在发生......

你的外壳好像是用32位运算和您的号码被溢出的格式。

此外,shell脚本中的所有命令参数都是字符串,因此除非参数中的字符对shell解析器有意义,否则引号将根本不起作用。

壳牌if声明实际上正在运行the test(1) command,它以简写形式链接到[。 (然后它会忽略最后的]。)尽管该命令可能使用了相同的运算符进行数字和字符串比较,但碰巧该命令的设计方式使得运算符假定某种类型,并假定数字。

关于bash和ash(短划线),我在您的x ...示例中收到错误消息。

相关问题