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. mitprintf '%.0f\n' 28.5
, was28
ergibt statt der erwarteten29
):
awk -v item=30 -v total=70 'BEGIN { printf "%.0f\n", 100 * item / total }'
- Beachten Sie, wie
-v
wird verwendet, um Variablen fürawk
zu definieren -Skript, das eine saubere Trennung zwischen den einfachen Anführungszeichen ermöglicht und daher wörtlichawk
-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 vonawk
verwendet werden oben), also kann Folgendes funktionieren oder nicht (und ist die Mühe angesichts des einfacherenawk
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