0

My shell script look like this ,

sOneCount =5
sZeroCount=12
aa=`expr $sOneCount / $sZeroCount`
successRate=`expr $aa \* 100

since 5/12 results in 0.416 and then 0.416*100 it should give 41.6 but i am getting "successRate" as 0. Its rounding off the float value.

I want the final result should be 41 like this, please help me in this Thanks

harish
  • 9
  • 1
  • 3
  • 1
    yes, `awk` will simplify this. Please read at least [Awk Tutorial -- printf](http://grymoire.com/Unix/Awk.html#uh-27) and the **Format Specifiers** section below. Good luck. – shellter Aug 08 '19 at 13:49
  • It is highly unlikely that you are using a Bourne-style shell that does not support the standard POSIX arithmetic expression. Use `aa=$(( sOneCount / sZeroCount ))` and `successRate=$(( aa * 100 ))` instead. `expr` is obsolete except for regular-expression matching. (But more to the point, most shells don't support floating-point arithmetic; `zsh` is a notable exception.) – chepner Aug 08 '19 at 13:51
  • 2
    You can find quite comperhensive list of solutions here: https://stackoverflow.com/questions/12722095/how-do-i-use-floating-point-division-in-bash – J.L. Aug 08 '19 at 14:05

4 Answers4

2

Bash, and probably other similar shells, doesn't support floating point operations:

Evaluation is done in fixed-width integers with no check for overflow

http://man7.org/linux/man-pages/man1/bash.1.html#ARITHMETIC_EVALUATION

You can use bc instead, with the mathlib operations enabled:

$ successRate=$(echo "${sOneCount} / ${sZeroCount} * 100" | bc -l)
$ echo ${successRate}
41.66666666666666666600
Murphy
  • 3,827
  • 4
  • 21
  • 35
2

You should be using awk, not shell, for the calculations (and probably whatever else you're doing too but we can't see the rest of your script):

$ cat tst.sh
#!/bin/env bash

sOneCount=$1
sZeroCount=$2

awk -v sOneCount="$sOneCount" -v sZeroCount="$sZeroCount" 'BEGIN{
    aa = (sZeroCount == 0 ? 0 : sOneCount / sZeroCount)
    successRate = aa * 100
    print successRate
    printf "%d\n", successRate
}'

$ ./tst.sh 5 12
41.6667
41

$ ./tst.sh 5 0
0
0

Note that it protects against a divide by zero error.

Ed Morton
  • 188,023
  • 17
  • 78
  • 185
1

Note in the expr man page(1) that the / operator gives you the quotient, implying this is interger-only arithmetic.

You can get the integral successRate by multiplying the numerator by 100 first

$ successRate=$( expr 100 \* "$sOneCount" / "$sZeroCount" )
$ echo "$successRate"
41

Or, in bash, you don't need to call out to expr -- use the builtin arithmetic expression syntax:

$ successRate=$(( 100 * sOneCount / sZeroCount ))
$ echo "$successRate"
41

(1): the man page for the BSD expr on my Mac is more explicit: / returns the result of "integer division" of "integer-valued arguments".

glenn jackman
  • 238,783
  • 38
  • 220
  • 352
1

You can easily write your own calculator/eval in awk for most basic cases

For example:

$ eval() { awk "BEGIN {print $1}"; }
$ x=4; y=7;
$ eval "$x/$y"
0.571429

$ rate=$(eval "$x/$y")
$ eval "$rate*100"
57.1429

or, with a slight change can accept more arguments

$ eval() { awk "BEGIN {print $*}"; }
$ eval "$x" / "$y" "*" 100
57.1429
karakfa
  • 66,216
  • 7
  • 41
  • 56