Shell: “a -lt b” ne signifie-t-il pas true si a est inférieur à b?

Je ne suis pas formé à Linux, mais je peux me débrouiller avec certaines recherches documentaires, mais je suis déconcerté.

J’ai trouvé un script qui permet de définir la date sur mon routeur dd wrt au démarrage, mais uniquement si la date actuelle est inférieure à la date stockée. Je peux partager tout le script si vous le souhaitez, mais cela se résume à cette déclaration qui ne s’évalue pas comme il se doit. Je mets les littéraux, plutôt que les variables, et il ne retourne toujours pas true, il exécute l’instruction “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 

Je m’attendrais à ce que “le premier semble moins que le second” mais ce n’est pas le cas … Est-ce un problème de débordement? J’ai essayé de faire une chaîne comme ça:

 if [ x021715402012 -lt x021815402012 ] 

et essayé de le mettre entre guillemets:

 if [ "x021715402012" -lt "x021815402012" ] 

il exécute toujours le rest. Est-ce que ” a -lt b ” ne signifie pas vrai si a est inférieur à b?

Tout aperçu de cela serait apprécié, je suis déconcerté!

On peut dire que les mnémoniques tels que -lt proviennent des comparateurs Fortran originaux tels que .LT. à partir de la fin des années 1950.

Oui, dans le shell, -lt effectue une comparaison numérique «inférieure à». (Attention, en Perl, les comparaisons numériques sont < etc, et les comparaisons de chaînes sont désignées par les opérateurs alphabétiques tels que -lt !)

Cependant, dans certains cas, peut-être beaucoup, la conversion et la comparaison peuvent être effectuées dans le format entier long local. Si vous êtes sur un ordinateur 32 bits, les valeurs que vous citez dépassent la plage de 32 bits (signée) d'un facteur d'environ 10. Sur une machine 64 bits, ou avec un shell qui utilise long long , vous seriez OK.

Les équivalents hexadécimaux des nombres décimaux sont 021715402012 = 0x50E56BD1C et 021815402012 = 0x5144C9E1C; ils ne peuvent pas être octaux à cause du 8. (Cependant, si le shell interprète le zéro initial comme étant «octal», alors le deuxième nombre est juste 021 ou 17 décimal car le 8 termine le nombre octal. Cependant, le 64- les bit-shell que j'ai testés (Mac OS X 10.7.3 et RHEL 5) semblaient tous deux les traiter en décimal, pas en octal.)

L'exemple de code ci-dessous, compilé sous 64 bits, donne la sortie suivante:

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

Compilé sous 32 bits, il donne la sortie suivante:

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

Si c'était ce qui se passait dans votre shell, le comportement de -lt serait expliqué. Vous pouvez le confirmer en testant si les deux valeurs sont -eq ; Contre-intuitivement, cela serait probablement vrai sous l'hypothèse que vous utilisez un shell 32 bits qui limite son arithmétique à long entiers signés long (32 bits).

 #include  #include  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; } 

Quel shell et quelle version utilisez-vous? Une chance d’un caractère de contrôle intégré quelque part? (Essayez de supprimer la nouvelle saisie du code.) Sur openSUSE 11.2 (x86_64):

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

Intéressant, cependant,

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

Cela me surprend car man bash dit que -lt effectue une comparaison arithmétique et une constante avec un 0 est interprétée comme octale. Donc, je m’attendrais à ce que cela teste si dix est inférieur à onze, car 012 base 8 = 8 + 2.

Est-ce que quelqu’un peut nous mettre au clair?

Quelques choses se passent …

Votre shell semble utiliser l’arithmétique 32 bits et vos chiffres débordent le format.

De plus, tous les parameters de commande dans les scripts shell sont des chaînes, donc les guillemets n’auront aucun effet à moins que les caractères d’un paramètre soient significatifs pour l’parsingur de shell.

L’instruction shell if exécute en fait la commande test (1) qui est liée à [ tant que raccourci. (Et puis, il ignore une finale ] . Bien que la commande ait pu utiliser le même opérateur pour les comparaisons numériques et de chaînes, la commande est conçue de telle manière que les opérateurs prennent un certain type et que -lt assume un caractère numérique.

Sur bash et ash (dash), je reçois un message d’erreur sur votre exemple x …

Je ne sais pas si votre shell utilise cette interprétation, mais voici ce que je pense:

021715402012 est un nombre octal à 11 chiffres. 021815402012 est un nombre octal à deux chiffres terminé par un chiffre non octal (le 8 ).

De 021715402012 et 021 , clairement le second est plus petit.

Concernant vos autres tentatives, la documentation pour le test et [ commandes indique que -lt est uniquement valide pour les arguments numériques, pas pour les chaînes.