GNU/Linux >> Znalost Linux >  >> Linux

Výpočet zaokrouhlených procent v Shell Script bez použití bc

Shell skript kompatibilní s POSIX je vyžadován pouze pro podporu integer aritmetika pomocí jazyka shellu ("je vyžadována pouze aritmetika dlouhého celého čísla se znaménkem"), takže čistý shell řešení musí emulovat aritmetika s plovoucí desetinnou čárkou:

item=30
total=70

percent=$(( 100 * item / total + (1000 * item / total % 10 >= 5 ? 1 : 0) ))
  • 100 * item / total získá zkrácené výsledek celého čísla dělení v procentech.
  • 1000 * item / total % 10 >= 5 ? 1 : 0 vypočítá 1. desetinné místo, a pokud je rovno nebo větší než 5, přidá k výsledku celého čísla 1, aby se zaokrouhlilo nahoru.
  • Všimněte si, že ne je třeba před odkazy na proměnné přidat $ uvnitř aritmetické expanze $((...)) .

Pokud - v rozporu s premisou otázky - použití externích nástrojů je přijatelné:

  • awk nabízí jednoduché řešení, které však přichází s varováním že používá skutečnou binárku s dvojitou přesností hodnoty s plovoucí desetinnou čárkou, a proto mohou přinést neočekávané výsledky v desítkové soustavě reprezentace – např. zkuste printf '%.0f\n' 28.5 , což dává 28 spíše než očekávaných 29 ):
awk -v item=30 -v total=70 'BEGIN { printf "%.0f\n", 100 * item / total }'
  • Všimněte si, jak -v se používá k definování proměnných pro awk skript, který umožňuje čisté oddělení mezi jednou citací a tedy doslova awk skript a všechny hodnoty předané z shell .
  • Naopak, i když bc je nástroj POSIX (a proto lze očekávat, že bude přítomen na většině platforem podobných Unixu) a provádí libovolnou přesnost aritmetika, vždy se zkrátí výsledky, takže zaokrouhlení musí provést jiný užitečnost; printf , nicméně i když se v zásadě jedná o nástroj POSIX, není vyžadován pro podporu specifikátorů formátu s plovoucí desetinnou čárkou (jak se používají v awk výše), takže následující může, ale nemusí fungovat (a nestojí to za problémy, vzhledem k jednoduššímu awk řešení a vzhledem k tomu, že problémy s přesností kvůli aritmetice s plovoucí desetinnou čárkou jsou zpět na obrázku):
# !! 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
)"


Použijte AWK (žádné bash-ismy):

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

Vezmeme-li 2 * původní výpočet procent a získáme z toho modulo 2, získáme přírůstek pro zaokrouhlení.

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

echo $percent
43

(testováno s bash, ash, dash a ksh)

Toto je rychlejší implementace než spouštění koprocesu 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. Shell Script pro odeslání e-mailu s upozorněním, pokud využití disku překročí 90 %?

  2. Jak vložit spustitelný binární soubor do skriptu Shell bez dalších nástrojů?

  3. Xml bez Lf Chcete to udělat hezký pomocí Sed Command v Shell?

  1. Odesílání HTML pošty pomocí shell skriptu

  2. Bash skript:Použití příkazu script z bash skriptu pro protokolování relace

  3. Aktuální adresář skriptu Shell?

  1. Časový limit ve skriptu Shell?

  2. Použití příkazu passwd ze skriptu shellu

  3. Iterujte přes proměnnou $PATH pomocí skriptu shellu