GNU/Linux >> Tutoriels Linux >  >> Linux

Calcul du pourcentage arrondi dans Shell Script sans utiliser bc

Un script shell compatible POSIX n'est requis que pour prendre en charge integer arithmétique utilisant le langage shell ("seule l'arithmétique des entiers longs signés est requise"), donc un shell pur la solution doit émuler arithmétique à virgule flottante :

item=30
total=70

percent=$(( 100 * item / total + (1000 * item / total % 10 >= 5 ? 1 : 0) ))
  • 100 * item / total donne le tronqué résultat de l'entier division en pourcentage.
  • 1000 * item / total % 10 >= 5 ? 1 : 0 calcule la 1ère décimale, et si elle est égale ou supérieure à 5, ajoute 1 au résultat entier afin de l'arrondir.
  • Notez qu'il n'y a non besoin de préfixer les références de variables avec $ à l'intérieur d'un développement arithmétique $((...)) .

Si - contrairement à la prémisse de la question - utilisation d'utilitaires externes est acceptable :

  • awk offre un simple solution, qui, cependant, s'accompagne de la mise en garde qu'il utilise un vrai binaire double précision valeurs à virgule flottante et peut donc donner des résultats inattendus en décimal représentation - par exemple, essayez printf '%.0f\n' 28.5 , ce qui donne 28 plutôt que le 29 attendu ):
awk -v item=30 -v total=70 'BEGIN { printf "%.0f\n", 100 * item / total }'
  • Notez comment -v est utilisé pour définir des variables pour le awk script, qui permet une séparation nette entre les guillemets simples et donc littéral awk script et toutes les valeurs qui lui sont transmises depuis le shell .
  • En revanche, même si bc est un utilitaire POSIX (et on peut donc s'attendre à ce qu'il soit présent sur la plupart des plates-formes de type Unix) et effectue une précision arbitraire arithmétique, il tronque invariablement les résultats, de sorte que arrondir doit être exécuté par un autre utilitaire; printf , cependant, même s'il s'agit en principe d'un utilitaire POSIX, il n'est pas nécessaire pour prendre en charge les spécificateurs de format à virgule flottante (comme ceux utilisés dans awk ci-dessus), donc ce qui suit peut ou peut ne pas fonctionner (et n'en vaut pas la peine, étant donné le plus simple awk solution, et étant donné que les problèmes de précision dus à l'arithmétique en virgule flottante sont de retour dans l'image) :
# !! 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
)"


Utilisez AWK (pas de bash-ismes) :

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

Prendre 2 * le calcul du pourcentage d'origine et obtenir le modulo 2 de celui-ci fournit l'incrément pour l'arrondi.

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

echo $percent
43

(testé avec bash, ash, dash et ksh)

Il s'agit d'une implémentation plus rapide que le déclenchement d'un coprocessus 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. Expiration du délai dans un script shell ?

  2. Utilisation de la commande passwd à partir d'un script shell

  3. Envoi de courrier HTML à l'aide d'un script shell

  4. Vérifier la connectivité de la base de données à l'aide du script Shell

  5. Comment rechercher des fichiers à l'aide de regex dans le script shell Linux

Comprendre facilement les commandes Shell à l'aide du script "Explain Shell" sous Linux

Script bash :utilisation de la commande de script d'un script bash pour la journalisation d'une session

Ajouter une colonne à la fin du fichier CSV en utilisant 'awk' dans le script BASH

Le script Shell fonctionne bien sans ligne shebang? Pourquoi?

Obtenir l'adresse MAC à l'aide du script shell

Comment exécuter un fichier sans extension .sh dans le shell