GNU/Linux >> Linux Esercitazione >  >> Linux

Calcolo della percentuale arrotondata in Shell Script senza utilizzare bc

Uno script shell conforme a POSIX è richiesto solo per supportare integer aritmetica usando il linguaggio della shell ("è richiesta solo l'aritmetica di interi lunghi con segno"), quindi una shell pura la soluzione deve emulare aritmetica in virgola mobile:

item=30
total=70

percent=$(( 100 * item / total + (1000 * item / total % 10 >= 5 ? 1 : 0) ))
  • 100 * item / total restituisce il troncato risultato dell'intero divisione in percentuale.
  • 1000 * item / total % 10 >= 5 ? 1 : 0 calcola la prima cifra decimale e, se è uguale o maggiore di 5, aggiunge 1 al risultato intero per arrotondarlo.
  • Nota come no è necessario prefissare i riferimenti alle variabili con $ all'interno di un'espansione aritmetica $((...)) .

Se - in contraddizione con la premessa della domanda - uso di utilità esterne è accettabile:

  • awk offre un semplice soluzione, che, tuttavia, viene fornita con l'avvertimento che utilizza un vero binario a doppia precisione valori in virgola mobile e potrebbero pertanto produrre risultati imprevisti in decimal rappresentazione - ad esempio, prova printf '%.0f\n' 28.5 , che restituisce 28 piuttosto che il previsto 29 ):
awk -v item=30 -v total=70 'BEGIN { printf "%.0f\n", 100 * item / total }'
  • Notare come -v è usato per definire le variabili per awk script, che consente una netta separazione tra le virgolette singole e quindi letterale awk script e tutti i valori che gli vengono passati dalla shell .
  • Al contrario, anche se bc è un'utilità POSIX (e ci si può quindi aspettare che sia presente sulla maggior parte delle piattaforme simili a Unix) ed esegue precisione arbitraria in aritmetica, invariabilmente tronca i risultati, in modo che l'arrotondamento deve essere eseguito da un altro utilità; printf , tuttavia, anche se in linea di principio è un'utilità POSIX, non è richiesta per supportare identificatori di formato a virgola mobile (come quelli usati all'interno di awk sopra), quindi quanto segue potrebbe o meno funzionare (e non ne vale la pena, dato il più semplice awk soluzione, e dato che i problemi di precisione dovuti all'aritmetica in virgola mobile sono tornati in scena):
# !! 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 (senza bash-ism):

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

Prendendo 2 * il calcolo percentuale originale e ottenendo il modulo 2 di esso fornisce l'incremento per l'arrotondamento.

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

echo $percent
43

(testato con bash, ash, dash e ksh)

Questa è un'implementazione più veloce rispetto all'attivazione di un coprocesso 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. Timeout in uno script di shell?

  2. Script di shell per inviare un'e-mail di avviso se l'utilizzo del disco supera il 90%?

  3. Modo per incorporare un binario eseguibile in uno script di shell senza strumenti aggiuntivi?

  4. Un XML senza Lf Vuoi renderlo carino usando il comando Sed in Shell?

  5. Invio di posta HTML utilizzando uno script di shell

Comprendere facilmente i comandi della shell utilizzando lo script "Explain Shell" in Linux

Utilizzando il comando passwd dall'interno di uno script di shell

Script bash:utilizzo del comando script da uno script bash per la registrazione di una sessione

Ottieni l'indirizzo MAC usando lo script della shell

Come eseguire un file senza estensione .sh nella shell

Shell:è possibile ritardare un comando senza usare `sleep`?