2012-02-19 121 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 ...示例中收到錯誤消息。

相關問題