GNU/Linux >> Tutoriales Linux >  >> Linux

Cálculo del porcentaje redondeado en Shell Script sin usar bc

Solo se requiere un script de shell compatible con POSIX para admitir integer aritmética utilizando el lenguaje shell ("solo se requiere aritmética de enteros largos con signo"), por lo que un shell puro la solución debe emular aritmética de coma flotante:

item=30
total=70

percent=$(( 100 * item / total + (1000 * item / total % 10 >= 5 ? 1 : 0) ))
  • 100 * item / total produce el truncado resultado del entero división como porcentaje.
  • 1000 * item / total % 10 >= 5 ? 1 : 0 calcula el 1er lugar decimal, y si es igual o mayor a 5, suma 1 al resultado entero para redondearlo.
  • Tenga en cuenta que no necesita prefijar referencias variables con $ dentro de una expansión aritmética $((...)) .

Si - en contradicción con la premisa de la pregunta - uso de utilidades externas es aceptable:

  • awk ofrece un simple solución, que, sin embargo, viene con la advertencia que utiliza verdadero binario de doble precisión valores de coma flotante y, por lo tanto, pueden producir resultados inesperados en decimal representación - por ejemplo, intente printf '%.0f\n' 28.5 , que produce 28 en lugar del esperado 29 ):
awk -v item=30 -v total=70 'BEGIN { printf "%.0f\n", 100 * item / total }'
  • Observe cómo -v se utiliza para definir variables para el awk script, que permite una separación clara entre las comillas simples y por lo tanto literal awk script y cualquier valor que se le haya pasado desde el shell .
  • Por el contrario, aunque bc es una utilidad POSIX (y, por lo tanto, se puede esperar que esté presente en la mayoría de las plataformas similares a Unix) y realiza precisión arbitraria aritmética, invariablemente trunca los resultados, de modo que redondeando debe ser realizado por otro utilidad; printf , sin embargo, aunque en principio es una utilidad POSIX, no se requiere para admitir especificadores de formato de coma flotante (como los que se usan dentro de awk anterior), por lo que lo siguiente puede o no funcionar (y no vale la pena, dado el awk más simple solución, y dado que los problemas de precisión debido a la aritmética de punto flotante están de vuelta en la imagen):
# !! This MAY work on your platform, but is NOT POSIX-compliant:
# `-l` tells `bc` to set the precision to 20 decimal places, `printf '%.0f\n'`
# then performs the rounding to an integer.
item=20 total=70
printf '%.0f\n' "$(bc -l <<EOF
100 * $item / $total
EOF
)"


Usa AWK (sin bash-ismos):

item=30
total=70
percent=$(awk "BEGIN { pc=100*${item}/${total}; i=int(pc); print (pc-i<0.5)?i:i+1 }")

echo $percent
43

Tomando 2 * el cálculo porcentual original y obteniendo el módulo 2 proporciona el incremento para el redondeo.

item=30
total=70
percent=$((200*$item/$total % 2 + 100*$item/$total))

echo $percent
43

(probado con bash, ash, dash y ksh)

Esta es una implementación más rápida que disparar un coproceso AWK:

$ pa() { for i in `seq 0 1000`; do pc=$(awk "BEGIN { pc=100*${item}/${total}; i=int(pc); print (pc-i<0.5)?i:i+1 }"); done; }
$ time pa

real    0m24.686s
user    0m0.376s
sys     0m22.828s

$ pb() { for i in `seq 0 1000`; do pc=$((200*$item/$total % 2 + 100*$item/$total)); done; }
$ time pb

real    0m0.035s
user    0m0.000s
sys     0m0.012s

Linux
  1. Manera de incrustar un binario ejecutable en un script de Shell sin herramientas adicionales?

  2. ¿Un Xml sin Lf quiere hacerlo bonito usando el comando Sed en Shell?

  3. Usando el comando passwd desde dentro de un script de shell

  4. Envío de correo HTML usando un script de shell

  5. Verifique la conectividad de la base de datos usando el script Shell

Comprender fácilmente los comandos de Shell usando el script "Explain Shell" en Linux

Agregar columna al final del archivo CSV usando 'awk' en el script BASH

Shell script directorio actual?

Iterar sobre la variable $ PATH usando el script de shell

Usando grep vs awk

Shell:¿es posible retrasar un comando sin usar `sleep`?