2012-02-19 45 views
6

Tôi không được đào tạo trong Linux, nhưng tôi có thể lộn xộn thông qua một số tra cứu tài liệu, nhưng tôi bị bối rối.Shell: "a -lt b" không có nghĩa là true nếu a nhỏ hơn b?

Tôi tìm thấy tập lệnh giúp đặt ngày trên bộ định tuyến dd wrt khi khởi động, nhưng chỉ khi ngày hiện tại nhỏ hơn ngày được lưu trữ. Tôi có thể chia sẻ toàn bộ kịch bản nếu bạn muốn, nhưng nó tóm lại tuyên bố này không đánh giá đúng khi tôi mong đợi nó. Tôi đang đặt các chữ cái vào, thay vì các biến, và nó vẫn không trả lại đúng, nó thực thi câu lệnh "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 

Tôi mong đợi "lần đầu tiên có vẻ nhỏ hơn giây" nhưng điều này không phải là trường hợp ... Đây có phải là sự cố tràn không? Tôi cố gắng để làm cho nó một chuỗi so sánh như thế này:

if [ x021715402012 -lt x021815402012 ] 

và cố gắng đặt nó trong dấu ngoặc kép:

if [ "x021715402012" -lt "x021815402012" ] 

nó luôn luôn thực thi khác. Có "a -lt b" không có nghĩa là true nếu a nhỏ hơn b?

Bất kỳ thông tin chi tiết nào về điều này đều sẽ được đánh giá cao, tôi bị bối rối!

+0

Hoạt động tốt trong 'bash' trên máy Mac của tôi. – kindall

+1

Hmm nó in "đầu tiên có vẻ ít hơn thứ hai" đối với tôi khi tôi kiểm tra ví dụ của bạn. Phiên bản bash hay sh là gì? Nếu bạn muốn biết thêm thông tin về -lt, bạn có thể kiểm tra 'help test',' help ['hoặc' man test'. –

+0

Cũng hoạt động tốt trên bộ định tuyến openwrt của tôi. Nhưng tôi rõ ràng có một thực hiện khác nhau mà bạn làm, bởi vì tôi cung cấp cho "số lượng xấu" với 'x' bao gồm. –

Trả lời

3

Các ghi nhớ như -lt có thể được cho là đến từ các so sánh Fortran gốc như .LT. từ cuối những năm 1950.

Có, trong vỏ, -lt thực hiện so sánh số 'ít hơn'. (Tuy nhiên, hãy lưu ý rằng trong Perl, các so sánh số là < vv và các so sánh chuỗi được biểu thị bởi các toán tử chữ cái như -lt!)

Tuy nhiên, trong một số, có lẽ nhiều, trình bao chuyển đổi và so sánh cũng có thể được thực hiện theo định dạng số nguyên dài địa phương. Nếu bạn đang sử dụng máy 32 bit, các giá trị bạn trích dẫn vượt quá phạm vi 32 bit (đã ký) theo hệ số 10 hoặc hơn. Trên máy tính 64 bit hoặc với vỏ có sử dụng long long, bạn sẽ không sao.

Tương đương hex của các số thập phân là 021715402012 = 0x50E56BD1C và 021815402012 = 0x5144C9E1C; chúng không thể là bát phân bởi vì 8. (Tuy nhiên, nếu shell giải thích số 0 đứng đầu là 'bát phân', thì số thứ hai chỉ là 021 hoặc 17 số thập phân vì số 8 kết thúc số bát phân. vỏ chút tôi thử nghiệm trên (Mac OS X 10.7.3 và RHEL 5) cả hai dường như đối xử với họ như thập phân, bát phân không)

Đoạn mã ví dụ dưới đây, biên soạn dưới 64-bit mang lại kết quả như sau:.

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

Biên soạn dưới 32-bit, nó mang lại kết quả như sau:

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

Nếu đây là những gì đã xảy ra trong vỏ của bạn, sau đó hành vi kết quả của -lt sẽ được giải thích. Bạn có thể xác nhận nó bằng cách kiểm tra xem hai giá trị là -eq; chống trực quan, điều này có lẽ sẽ đánh giá đúng theo giả thuyết rằng bạn đang sử dụng một trình bao 32 bit giới hạn số học của nó thành long (32-bit) số nguyên đã ký.

#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

Cảm ơn bạn @ Jonathan cho phản ứng toàn diện như vậy. Tôi tin rằng vấn đề là tình trạng tràn, họ chỉ đơn giản là cả hai quá lớn. Tôi đã xóa năm 2012 ở cuối mỗi lần và nó bắt đầu hoạt động như mong đợi, ngay cả với số 0 đứng đầu. Vì vậy, lý thuyết so sánh bát phân không phải là trường hợp ở đây. Như những con số này thực sự ngày tháng theo thứ tự kỳ lạ của các ký tự (mmddHHMMyyyy) tôi sẽ chia so sánh để so sánh những năm đầu tiên sau đó mmddHHMM, và tôi tin rằng sẽ giải quyết vấn đề này. Cảm ơn một lần nữa! –

1

Bạn đang sử dụng phiên bản và phiên bản nào? Bất kỳ cơ hội của một nhân vật điều khiển nhúng ở đâu đó? (Hãy thử xóa lại gõ mã.) Trên openSUSE 11.2 (x86_64):

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

Điều thú vị, tuy nhiên,

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

này làm tôi ngạc nhiên vì man bash nói rằng -lt thực hiện một sự so sánh số học, và một hằng số với số 0 đứng đầu được hiểu là bát phân. Vì vậy, tôi mong đợi điều này để kiểm tra xem mười là ít hơn mười một, bởi vì 012 cơ sở 8 = 8 + 2.

Ai đó có thể đặt chúng tôi thẳng?

+0

Thú vị tìm thấy ở đó. – hochl

+0

Vỏ của bạn không diễn giải bát phân .... và có lẽ là của Brian. –

+1

Tôi cũng nhận được "không". Vấn đề là @Jonathan đã nói ở trên - những con số quá lớn và như vậy, tôi đoán, được hiểu là giống nhau. Tôi đã xác nhận điều này bằng cách thay đổi -lt thành -gt. Nó vẫn nói "không" Nếu không phải là gt và không lt, phải bằng nhau, thì ... trong con mắt của một bộ định tuyến nhỏ. –

0

Tôi không chắc chắn nếu vỏ cụ thể của bạn đang sử dụng cách giải thích này, nhưng đây là những gì tôi nghĩ đang xảy ra:

021715402012 là một số bát phân 11 chữ số. 021815402012 là số bát phân có hai chữ số được kết thúc bằng một chữ số không bát phân (số 8).

Trong số 021715402012021, rõ ràng là giây thứ hai nhỏ hơn.

Về các nỗ lực khác của bạn, tài liệu cho các lệnh test[ cho biết rằng -lt chỉ hợp lệ cho đối số dạng số, không phải là chuỗi.

+0

Giả thuyết thú vị; xét nghiệm axit là để giảm số 0 hàng đầu. Phiên bản 'x' sẽ so sánh bằng nhau, đúng không, bởi vì cả hai chuỗi đều đánh giá bằng không một số. –

+0

@JonathanLeffler: Có thể. Hãy để tôi xem nếu hộp openwrt của tôi có thể tái tạo hành vi ban đầu ....thực sự tôi nhận được hành vi "mong đợi" với số không đứng đầu, và với 'x' tôi nhận được "ash: x021715402012: số kém". –

1

Một vài điều đang xảy ra ...

vỏ của bạn dường như được sử dụng 32-bit số học và số của bạn đang tràn định dạng.

Ngoài ra, tất cả các tham số lệnh trong tập lệnh shell là chuỗi, vì vậy các dấu ngoặc kép sẽ không có hiệu lực trừ khi các ký tự trong tham số quan trọng đối với trình phân tích cú pháp.

Tuyên bố vỏ if thực sự đang chạy the test(1) command được liên kết với [ dưới dạng viết tắt. Mặc dù lệnh này có thể đã sử dụng toán tử giống nhau để so sánh số và chuỗi, vì nó xảy ra lệnh được thiết kế theo cách mà các toán tử giả định một kiểu nhất định và -lt giả định số.

Trên bash và tro (dấu gạch ngang), tôi nhận được thông báo lỗi trên ví dụ x ... của bạn.

Các vấn đề liên quan