
Mi búsqueda esta mañana fue sobre cómo podría comparar dos números decimales en bash, y llegué a esta respuesta:Cómo comparar con un número de coma flotante en un script de shell. Éste, sin embargo, no incluyeesta respuesta aquí:
$ [[ ((3.56 < 2.90)) ]]; echo $?
1
$ [[ ((3.56 < 4.90)) ]]; echo $?
0
Teniendo en cuenta que la respuesta ha sido rechazada y parece una especie de bashismo inusual, ¿es confiable esta evaluación aritmética por su precisión?
Respuesta1
bash
No entiende los números de punto flotante. Página del manual
de cotizaciones bash
, secciónEVALUACIÓN ARITMÉTICA:
La evaluación se realiza en números enteros de ancho fijo […].
Entonces ((3 < 4))
o ((3 < 2))
son en realidad expresiones aritméticas correctas. Puedes escribir lo siguiente:
$ echo "$((3 < 4)) -- $((3 < 2))"
producción:
1 -- 0
Pero $ echo $((3.3 < 3.6))
devolverá un mensaje de error de sintaxis. En su ejemplo, en realidad está comparando cadenas. De ahí algún ejemplo:
$ [[ ((3.56 < 04.90)) ]]; echo $?
producción:
1
Respuesta2
El interior [[...]]
<
es para comparar cadenas.
Entonces [[ 3.56 < 2.90 ]]
or [[ (3.56 < 2.90) ]]
or [[ ((3.56 < 2.90)) ]]
or [[ (((3.56 < 2.90))) ]]
... es simplemente comparar léxicamente la 3.56
cadena con la 2.90
cadena (y léxicamente, 3
es mayor que, 10
por ejemplo).
Para comparación de números enteros, es [[ 3 -lt 2 ]]
o (( 3 < 2 ))
. Si desea una comparación de punto flotante, necesita o ksh93
una utilidad externa como o ; No puedo hacerlo.zsh
yash
awk
perl
bash
Por ejemplo, podrías definir una función como:
compare() (IFS=" "
exec awk "BEGIN{if (!($*)) exit(1)}"
)
Que podrías usar, por ejemplo, como:
if compare '1.5*10 < 1e3'; then
echo less
fi
O incluso para eso importa:
if compare '"bar" < "foo"'...
para hacer comparaciones de cadenas.
No pase datos proporcionados externamente sin control a esa compare
función, ya que constituiría una vulnerabilidad de inyección de comandos (los datos se interpretan como awk
código, awk
pueden ejecutar comandos con él, system()
por ejemplo).