GNU/Linux >> LINUX-Kenntnisse >  >> Linux

Berechnung des gerundeten Prozentsatzes in Shell Script ohne Verwendung von bc

Ein POSIX-kompatibles Shell-Skript ist nur erforderlich, um Integer zu unterstützen Arithmetik mit der Shell-Sprache ("nur vorzeichenbehaftete Long-Integer-Arithmetik ist erforderlich"), also eine reine Shell Lösung muss emulieren Fließkomma-Arithmetik:

item=30
total=70

percent=$(( 100 * item / total + (1000 * item / total % 10 >= 5 ? 1 : 0) ))
  • 100 * item / total ergibt das abgeschnittene Ergebnis der Ganzzahl Teilung in Prozent.
  • 1000 * item / total % 10 >= 5 ? 1 : 0 berechnet die 1. Dezimalstelle und addiert, wenn sie gleich oder größer als 5 ist, 1 zum ganzzahligen Ergebnis, um es aufzurunden.
  • Beachten Sie, dass es nein gibt Variablenreferenzen muss $ vorangestellt werden innerhalb einer arithmetischen Erweiterung $((...)) .

Wenn - entgegen der Prämisse der Frage - die Verwendung von externen Dienstprogrammen ist akzeptabel:

  • awk bietet eine einfache Lösung, die jedoch mit dem Vorbehalt einhergeht dass es echte Binär mit doppelter Genauigkeit verwendet Fließkommazahlen und kann daher zu unerwarteten dezimalen Ergebnissen führen Darstellung - versuchen Sie es z. B. mit printf '%.0f\n' 28.5 , was 28 ergibt statt der erwarteten 29 ):
awk -v item=30 -v total=70 'BEGIN { printf "%.0f\n", 100 * item / total }'
  • Beachten Sie, wie -v wird verwendet, um Variablen für awk zu definieren -Skript, das eine saubere Trennung zwischen den einfachen Anführungszeichen ermöglicht und daher wörtlich awk -Skript und alle Werte, die ihm von der Shell übergeben werden .
  • Im Gegensatz dazu, obwohl bc ist ein POSIX-Dienstprogramm (und daher auf den meisten Unix-ähnlichen Plattformen vorhanden sein) und führt beliebige Genauigkeit aus Arithmetik, es wird ausnahmslos abgeschnitten die Ergebnisse, so dass runden muss von einem anderen durchgeführt werden Dienstprogramm; printf , obwohl es im Prinzip ein POSIX-Dienstprogramm ist, ist nicht erforderlich zur Unterstützung von Fließkommaformatbezeichnern (wie sie innerhalb von awk verwendet werden oben), also kann Folgendes funktionieren oder nicht (und ist die Mühe angesichts des einfacheren awk nicht wert Lösung, und da Präzisionsprobleme aufgrund von Fließkomma-Arithmetik wieder im Bild sind):
# !! 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
)"


Verwenden Sie AWK (keine Bashismen):

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

Wenn man 2 * der ursprünglichen Prozentberechnung nimmt und Modulo 2 davon erhält, erhält man das Inkrement für die Rundung.

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

echo $percent
43

(getestet mit bash, ash, dash und ksh)

Dies ist eine schnellere Implementierung als das Auslösen eines AWK-Coprozesses:

$ 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. Zeitüberschreitung in einem Shell-Skript?

  2. Shell-Skript zum Senden einer Warn-E-Mail, wenn die Festplattennutzung 90 % überschreitet?

  3. Möglichkeit zum Einbetten einer ausführbaren Binärdatei in ein Shell-Skript ohne zusätzliche Tools?

  4. Ein XML ohne Lf Möchten Sie es mit dem Sed-Befehl in der Shell hübsch machen?

  5. So suchen Sie nach Dateien mit Regex im Linux-Shell-Skript

Einfaches Verständnis von Shell-Befehlen mit dem Skript „Explain Shell“ in Linux

Überprüfen Sie die Datenbankkonnektivität mit Shell-Skript

Aktuelles Verzeichnis des Shell-Skripts?

Shell-Skript funktioniert gut ohne Shebang-Zeile? Wieso den?

Rufen Sie die MAC-Adresse mit Shell-Skript ab

Verwenden von grep vs. awk