2012-02-19 19 views
6

No estoy capacitado en Linux, pero puedo hacer algunas búsquedas de documentos, pero estoy perplejo.Shell: ¿"a -lt b" no significa verdadero si a es menor que b?

Encontré una secuencia de comandos que ayuda a establecer la fecha en mi enrutador dd wrt cuando se inicia, pero solo si la fecha actual es menor que la fecha almacenada. Puedo compartir todo el script si lo desea, pero se reduce a esta afirmación que no se evalúa como verdadera cuando lo espero. Estoy poniendo en los literales, en lugar de las variables, y todavía no vuelve verdadera, ejecuta el "otro" declaración:

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 

Yo esperaría "la primera parece menor que el segundo", pero esto no es el caso ... ¿Es un problema de desbordamiento? Traté de hacer que una cadena comparar de esta manera:

if [ x021715402012 -lt x021815402012 ] 

y trató de ponerlo entre comillas:

if [ "x021715402012" -lt "x021815402012" ] 

siempre ejecuta la persona. ¿No significa "a -lt b" verdadero si a es menor que b?

¡Cualquier apreciación de esto sería apreciada, estoy perplejo!

+0

Funciona bien en 'bash' en mi Mac. – kindall

+1

Hmm imprime "la primera parece menos que la segunda" para mí cuando pruebo tu ejemplo. ¿Qué versión de bash o sh es esta? Si desea obtener más información sobre -lt, etc., puede marcar 'help test',' help'' o 'man test'. –

+0

También funciona bien en mi enrutador openwrt. Pero claramente tengo una implementación diferente que tú haces, porque la mía da "mala cantidad" con la 'x' incluida. –

Respuesta

3

Los mnemotécnicos como -lt podrían decirse que proceden de los comparadores Fortran originales, como .LT. de finales de la década de 1950.

Sí, en el depósito, -lt hace una comparación numérica 'menor que'. (Tenga en cuenta, sin embargo, que en Perl, las comparaciones numéricas son < etc., y las comparaciones de cadenas se denotan por los operadores alfabéticos como -lt!)

Sin embargo, en algunos, quizás muchos, shells la conversión y la comparación pueden realizarse en el formato entero largo local. Si está en una máquina de 32 bits, los valores que cita superan el rango de 32 bits (firmado) por un factor de 10 o más. En una máquina de 64 bits, o con un shell que usa long long, estarás bien.

Los equivalentes hexadecimales de los números decimales son 021715402012 = 0x50E56BD1C y 021815402012 = 0x5144C9E1C; no pueden ser octal debido a 8. (Sin embargo, si el intérprete de comandos interpreta el cero inicial como 'octal', entonces el segundo número es solo 021 o 17 decimal porque el 8 termina el número octal. conchas bits I probados en (Mac OS X 10.7.3 y RHEL 5) ambos parecían tratarlos como decimal, no octal)

el código de ejemplo a continuación, compilado bajo 64 bits da el siguiente resultado:.

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

Compilado bajo de 32 bits, se da el siguiente resultado:

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

Si esto era qué sucedió en tu caparazón, entonces se explicaría el comportamiento resultante de -lt. Puede confirmarlo probando si los dos valores son -eq; de forma contra-intuitiva, esto probablemente se evaluaría como verdadero bajo la hipótesis de que está utilizando un shell de 32 bits que limita su aritmética a long (32 bits) con números enteros con signo.

#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

Gracias @Jonathan por una respuesta tan completa. Creo que el problema es la condición de desbordamiento, simplemente son demasiado grandes. Quité el 2012 al final de cada uno, y comenzó a actuar como se esperaba, incluso con el cero inicial. Entonces la teoría de comparación octal no fue el caso aquí. Como estos números son en realidad fechas en un extraño orden de caracteres (mmddHHMMyyyy), dividiré la comparación para comparar los años primero y luego el mmddHHMM, y creo que eso resolverá este problema. ¡Gracias de nuevo! –

1

¿Qué shell y versión estás usando? ¿Alguna posibilidad de tener un personaje de control incrustado en alguna parte? (Prueba a borrar volver a escribir el código.) En openSUSE 11.2 (x86_64):

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

Curiosamente, sin embargo,

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

Esto me sorprende porque man bash dice que -lt realiza una comparación aritmética, y una constante con un 0 inicial se interpreta como octal. Así que esperaría que esto pruebe si diez es menor que once, porque 012 base 8 = 8 + 2.

¿Alguien nos puede aclarar?

+0

Interesante encontrar allí. – hochl

+0

Tu caparazón no está interpretando octal ... y tal vez sea Brian's. –

+1

También obtuve "no". El problema era que, como dijo @Jonathan más arriba, los números eran demasiado grandes y, supongo, se interpretó que eran los mismos. Confirmé esto cambiando -lt a -gt. Todavía decía "no". Si no gt y no lt, debe ser igual, entonces ... a los ojos de un pequeño enrutador. –

0

no estoy seguro de si su cáscara en particular está utilizando esta interpretación, pero aquí es lo que creo que está ocurriendo:

021715402012 es un número octal de 11 dígitos. 021815402012 es un número octal de dos dígitos terminado por un dígito no octal (el 8).

De 021715402012 y 021, claramente el segundo es más pequeño.

En cuanto a sus otros intentos, la documentación para los comandos test y [ indica que -lt solo es válido para argumentos numéricos, no para cadenas.

+0

Interesante hipótesis; la prueba de ácido es caer el cero inicial. La versión 'x' se comparará igual, ¿no ?, porque ambas cadenas evalúan a cero un número. –

+0

@JonathanLeffler: Probablemente. Déjame ver si mi caja openwrt puede reproducir el comportamiento original ...en realidad obtengo el comportamiento "esperado" con los ceros a la izquierda, y con 'x' obtengo "ceniza: x021715402012: número malo". –

1

Algunas cosas están sucediendo ...

fuera te parece estar usando la aritmética de 32 bits y sus números están desbordando el formato.

Además, todos los parámetros de comando en los scripts de shell son cadenas, por lo que las comillas no tendrán ningún efecto a menos que los caracteres en un parámetro sean significativos para el analizador de shell.

La instrucción shell if se está ejecutando realmente the test(1) command que está vinculada a [ como una forma abreviada. (Y luego ignora un ] final). Aunque el comando podría haber usado el mismo operador para comparaciones numéricas y de cadenas, el comando está diseñado de tal manera que los operadores asumen un cierto tipo, y -lt asume que es numérico.

En bash y ceniza (guión) Aparece un mensaje de error en su x ... ejemplo.

Cuestiones relacionadas