bash: j'ai cassé [[<]]

14

J'écrivais un script bash et soudain ce comportement a commencé:

[[ 1 < 2 ]]; echo $?  # outputs 0
[[ 2 < 13 ]]; echo $? # outputs 1

mais -ltfonctionne bien:

[[ 1 -lt 2 ]]; echo $?  # outputs 0
[[ 2 -lt 13 ]]; echo $? # outputs 0

ai-je accidentellement écrasé d'une <manière ou d'une autre?

voici un script que j'ai écrit pour tester ce comportement:

#!/bin/bash

for a in {1..5}
do
    for b in {1..20}
    do
        [[ $a < $b ]] && echo $a $b
    done

    echo
done

voici la sortie:

1 2
1 3
1 4
1 5
1 6
1 7
1 8
1 9
1 10
1 11
1 12
1 13
1 14
1 15
1 16
1 17
1 18
1 19
1 20

2 3
2 4
2 5
2 6
2 7
2 8
2 9
2 20

3 4
3 5
3 6
3 7
3 8
3 9

4 5
4 6
4 7
4 8
4 9

5 6
5 7
5 8
5 9

changer <pour -ltdans le script donne une sortie normale ( 5 10apparaît par exemple).

Le redémarrage n'a rien changé.

Ma version bash est GNU bash, version 4.3.42 (1) -release (x86_64-pc-linux-gnu). Je suis sur Ubuntu 15.10. Je ne sais pas quelles autres informations sont pertinentes ici.

escargot en quête
la source
16
avec l' <opération, vous faites une comparaison de chaînes, tandis que l' -ltopérateur est une comparaison numérique, si vous regardez les résultats que vous avez répertoriés, vous vous en rendrez compte. Numériquement 2 est inférieur à 10, par ordre alphabétique, dans l'autre sens.
MelBurslan

Réponses:

51

Depuis la bashpage de manuel.

Lorsqu'ils sont utilisés avec [[, les opérateurs <et> trient lexicographiquement en utilisant les paramètres régionaux actuels.

De la sortie, il semble fonctionner comme prévu.

Steve
la source
35
En d'autres termes, lisez la page de manuel avant de supposer que vous avez trouvé un bogue. ;)
Wildcard
Vrai. Peut-être que le script sur lequel je travaillais à l'origine a commencé à fonctionner «correctement» (comme en échouant [[$ myvar <13]]) lorsque j'ai remarqué ce comportement. Y a-t-il quelque chose que je devrais faire pour cette question maintenant? Devons-nous sur ce site changer le titre pour inclure [résolu] ou quelque chose? Le titre devrait-il être changé de toute façon en quelque chose de plus descriptif?
escargot en quête
2
Non, ne changez pas le titre de la question. La coche à côté de cette réponse suffit pour indiquer que la question a été résolue.
saiarcot895
14
@Wildcard L'OP ne suppose pas qu'ils ont trouvé un bogue. Ils suggèrent explicitement qu'ils ont peut-être fait quelque chose pour modifier le comportement. Même le titre en suppose autant!
jpmc26
5

Que diriez-vous:

for a in {1..5}; 
do     
  for b in {1..20};     
  do         
    (( $a < $b )) && echo $a $b
  done      
  echo
done

Selon http://www.tldp.org/LDP/abs/html/dblparens.html

Semblable à la commande let, la construction ((...)) permet l'expansion et l'évaluation arithmétique. Dans sa forme la plus simple, a = $ ((5 + 3)) mettrait a à 5 + 3, ou 8. Cependant, cette construction entre parenthèses est également un mécanisme permettant la manipulation de style C de variables dans Bash, par exemple , ((var ++)).

PaulSmecker
la source
2
Vous manquez le point de la question - ce n'est pas "comment puis-je comparer ces valeurs?" mais "pourquoi se comporte-t-il ainsi?".
guntbert
7
Cela a déjà été répondu. Mais comme il voulait utiliser une expression arithmétique, il pourrait être utile de souligner qu'il existe des constructions qui vous permettent d'utiliser celles en shell.
PaulSmecker
3

Tout d'abord, [[ n'est pas POSIX et doit être évité.

Deuxièmement, si vous souhaitez utiliser <dans le cadre d'un test arithmétique, vous pouvez le faire, mais avec une syntaxe différente:

if [ $((2 < 13)) = 1 ]
then
  echo '2 is less than 13'
else
  echo '2 is greater or equal to 13'
fi

Ou:

if expr 2 '<' 13
then
  echo '2 is less than 13'
else
  echo '2 is greater or equal to 13'
fi
Steven Penny
la source