bash: me rompí [[<]]

14

Estaba escribiendo un script bash y de repente comenzó este comportamiento:

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

pero -ltfunciona bien:

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

¿Sobreescribí accidentalmente de <alguna manera?

Aquí hay un script que escribí para probar este comportamiento:

#!/bin/bash

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

    echo
done

Aquí está la salida:

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

cambiar <a -lten el script da una salida normal (se 5 10muestra, por ejemplo).

Reiniciar no cambió nada.

Mi versión bash es GNU bash, versión 4.3.42 (1) -release (x86_64-pc-linux-gnu). Estoy en Ubuntu 15.10. No sé qué otra información es relevante aquí.

caracol en una búsqueda
fuente
16
con la <operación, está haciendo una comparación de cadenas, mientras que el -ltoperador es una comparación numérica. Si observa los resultados que ha enumerado, se dará cuenta. Numéricamente 2 es menor que 10, alfabéticamente, al revés.
MelBurslan

Respuestas:

51

De la bashpágina del manual.

Cuando se usa con [[, los operadores <y> se ordenan lexicográficamente usando la localización actual.

Desde la salida, parece estar funcionando según lo diseñado.

Steve
fuente
35
En otras palabras, lea la página de manual antes de asumir que ha encontrado un error. ;)
Comodín
Cierto. Quizás el script en el que estaba trabajando originalmente comenzó a funcionar 'correctamente' (como al fallar [[$ myvar <13]]) cuando noté este comportamiento en ese momento. ¿Hay algo que deba hacer a esta pregunta ahora? ¿En este sitio cambiamos el título para incluir [resuelto] o algo así? ¿Debería cambiarse el título de todos modos a algo más descriptivo?
snail-on-a-quest
2
No, no cambies el título de la pregunta. La marca de verificación junto a esta respuesta es suficiente para indicar que la pregunta se ha resuelto.
saiarcot895
14
@Wildcard El OP no asume que encontraron un error. Sugieren explícitamente que tal vez hayan hecho algo para alterar el comportamiento. ¡Incluso el título asume lo mismo!
jpmc26
5

Qué tal si:

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

De acuerdo con http://www.tldp.org/LDP/abs/html/dblparens.html

Similar al comando let, la construcción ((...)) permite la expansión y evaluación aritmética. En su forma más simple, a = $ ((5 + 3)) establecería a a 5 + 3 u 8. Sin embargo, esta construcción de paréntesis dobles también es un mecanismo para permitir la manipulación de variables en estilo C en Bash, por ejemplo , ((var ++)).

PaulSmecker
fuente
2
Te estás perdiendo el punto de la pregunta: no es "¿cómo puedo comparar esos valores?" pero "¿por qué se comporta como lo hace?".
guntbert
77
Esto ya fue respondido. Pero como quería usar una expresión aritmética, podría valer la pena señalar que existen construcciones que le permiten usarlas en shell.
PaulSmecker
3

En primer lugar, [[ no es POSIX y debe evitarse.

En segundo lugar, si desea utilizarlo <como parte de una prueba aritmética, puede hacerlo, pero con una sintaxis diferente:

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

O:

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