Quiero comparar una variable de coma flotante con un entero. Sé que esto no es lo mejor que puedo hacer con bash, pero todo el guión ya está escrito en bash. $ number puede ser cualquier número entero. Si está por debajo o igual a 50, quiero la salida 1, para todos los demás quiero una salida con la otra variable k. Esto es lo que tengo hasta ahora:
number=43 test=$(echo "scale=2; $number/50" | bc -l) echo "$test" for k in {1..5} do if ["$test" -le 1] then echo "output" elif ["$test" -gt $k] then echo "output$k" fi done
Si bash con test = 0.43, el primer ciclo ni siquiera funciona. Creo que tiene que ver con un entero y una comparación de coma flotante, pero no puede hacer que funcione.
¿Algo que me falta?
PD: este [0.43: command not found
es lo que produce el terminal.
Bash no puede manejar carrozas. Pipe to bc
lugar:
if [ $(echo " $test > $k" | bc) -eq 1 ]
El error que ves es porque el comando de test
(es decir, el [
) necesita espacios antes y después
Es incluso mejor usar (( ... ))
ya que comparas números como este:
if (( $(bc <<< "$test > $k") ))
La parte del ciclo debería verse así:
if (( $(bc <<< "$test <= 1") )) then echo "output" elif (( $(bc <<< "$test > $k") )) then echo "output$k" fi
Las expresiones relacionales evalúan a 0, si la relación es falsa, y 1 si la relación es verdadera [ fuente ]. Sin embargo, tenga en cuenta que es un comportamiento de GNU bc
y no es un comstackdor de POSIX
.
Es una vieja pregunta, pero creo que tiene una respuesta adicional.
Mientras que la conexión a una calculadora de mayor precisión (bc o dc) funciona, es a costa de una bifurcación y un proceso adicional, ya que esas calculadoras no están incorporadas en bash. Una cosa que está incorporada, sin embargo, es printf
. Entonces, si puede tratar con sus números dentro de un número particular de decimales, puede “falsificar” comparaciones de coma flotante, con una función como esta:
#!/usr/bin/env bash function [[[ () { local LANG=C lhs rhs printf -v lhs '%07.3f' "$1"; lhs=${lhs/./} printf -v rhs '%07.3f' "$3"; rhs=${rhs/./} case "$2" in -lt) return $(( ! ( 10#$lhs < 10#$rhs ) )) ;; -le) return $(( ! ( 10#$lhs <= 10#$rhs ) )) ;; -eq) return $(( ! ( 10#$lhs == 10#$rhs ) )) ;; -ge) return $(( ! ( 10#$lhs >= 10#$rhs ) )) ;; -gt) return $(( ! ( 10#$lhs > 10#$rhs ) )) ;; esac } number=${1:-43} test=$(dc -e "2k $number 50 / p") echo "$test" for k in {1..5}; do if [[[ "$test" -le 1 ]]]; then echo "output" elif [[[ "$test" -gt "$k" ]]]; then echo "output $k" fi done
Algunas cosas para considerar aquí.
[[[
que sea linda. Puedes ponerle el nombre que quieras. ntest
o mynumericcomparison
o incluso [[[
. printf
es una función interna dentro de bash, por lo tanto, a pesar de que está en su camino, no cuesta una bifurcación. printf
. 10#
al comienzo de cada variable dentro de la statement del case
es forzar la comparación en la base 10, ya que un número sin relleno podría interpretarse como octal. Ver también: http://mywiki.wooledge.org/BashFAQ/022