Shell: "a -lt b" does not mean true if a is less than b?

I do not study on Linux, but I can get confused in some documents, but I'm at a dead end.

I found a script that helps set the date on my dd wrt router at startup, but only if the current date is less than the stored date. I can split the whole script if you want, but it comes down to the fact that this statement does not evaluate true when I expect it. I put literals, not variables, and it still does not return true, it executes an else statement:

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 

I would expect that "the first seems smaller than the second," but it is not ... Is this an overflow problem? I tried to make the line look like this:

 if [ x021715402012 -lt x021815402012 ] 

and tried to put it in quotation marks:

 if [ "x021715402012" -lt "x021815402012" ] 

he always does else. " a -lt b " does not mean true if a is less than b?

Any insight into this would be appreciated, I'm at a standstill!

+6
source share
4 answers

Mnemonics such as -lt can be said to come from original Fortran comparators such as .LT. since the late 1950s.

Yes, the -lt shell performs a numerical comparison of less. (Remember that in Perl, numerical comparisons are < , etc., and string comparisons are indicated by alphabetical operators such as -lt !)

However, in some, possibly many shells, the conversion and comparison can very well be done in a local long integer format. If you are on a 32-bit machine, the values ​​you specify exceed the 32-bit (signed) range by 10 times or so. On a 64-bit machine or with a shell using long long everything will be fine.

Sixteen equivalents of decimal numbers: 021715402012 = 0x50E56BD1C and 021815402012 = 0x5144C9E1C; they cannot be octal because of 8. (However, if the shell interprets the leading zero as β€œoctal”, then the second number is only 021 or 17 decimal, because 8 ends the octal number. However, the 64-bit shells I tested (Mac OS X 10.7.3 and RHEL 5) seemed to treat them as decimal rather than octal.)

The code example below, compiled under 64-bit, gives the following result:

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

Compiled under 32-bit, it gives the following result:

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

If it was in your shell, then the resulting -lt behavior will be explained. You can confirm this by checking if these two values ​​are -eq ; counter-intuitively, this will probably be evaluated as true under the hypothesis that you are using a 32-bit shell that limits its arithmetic to long (32-bit) integers.

 #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; } 
+3
source

What shell and version are you using? Is there a chance of an inline control? (Try removing the re-entry code.) In openSUSE 11.2 (x86_64):

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

Interesting however

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

This surprises me because man bash says that -lt performs arithmetic comparisons, and the constant with leading 0 is interpreted as octal. So I expect this to check if ten is less than eleven, because 012 base 8 = 8 + 2.

Can someone put us straight?

+1
source

A few things happen ...

Your shell seems to be using 32-bit arithmetic, and your numbers overwhelm the format.

In addition, all command parameters in shell scripts are strings, so the quotation marks will have no effect if the characters in the parameter are not significant to the parser.

The if actually runs the test (1) command , which is associated with [ as abbreviated. (And then he ignores the final one.)) Although the command could use the same operator for numerical and string comparisons, as this happens, the command is designed in such a way that the operators accept a certain type, and -lt takes numerical values.

In bash and ash (dash), I get an error on your example x ...

+1
source

I'm not sure if your particular shell uses this interpretation, but here what I think is going on:

021715402012 is an 11-digit octal number. 021815402012 is a two-digit octal number terminated by a non-octal digit ( 8 ).

Of 021715402012 and 021 , obviously, the second is less.

As for your other attempts, the documentation for the test and [ commands indicates that -lt is only valid for numeric arguments, not string.

0
source

Source: https://habr.com/ru/post/908804/


All Articles