Right now I am working on an assignment that involves advanced piping, and one of the questions involves calculating a percent and shortening it to 3 decimal places. I've managed to calculate the percent:

echo "$ERRORS" / "$TOTAL" \* 100 | bc -l

which gives the correct output: 2.64905226881102814400

ERRORS and TOTAL are both environment variables containing integers.

But I don't really know how to modify this command to only output 2.649 instead of the full number. I know there is a way to use something called scale with bc to shorten to a certain number of decimal places but I tried echo scale=3; "$ERRORS" / "$TOTAL" \* 100 | bc -l and it didn't work.

What am I doing wrong?

  • 1
    In general "it didn't work" expresses nothing much more than frustration. You should explain what happened or what didn't happen, how that differed from your expectation, and the precise text of any messages generated. (The reason for comparing against your expectation is so that we can validate whether it's your expectation or the code that needs addressing.) – roaima Jul 23 '20 at 22:05
  • In the spirit of "advanced piping": pipe the output from bc into | xargs printf '%.3f\n' – Paul_Pedant Jul 24 '20 at 14:37


$ ERRORS=1153 TOTAL=43525
$ echo "scale = 3; $ERRORS * 100 / $TOTAL" | bc

instead. See how in this case, scale = 3 is being fed to bc to set the scale variable of bc, which is the number of digits that it keeps after the radix upon division, and how we did the multiplication by 100 before the division.

Note that it's truncation, not rounding. 8 * 100 / 9, will become 88.888, not 88.889 for instance.

If your shell supports floating point arithmetics (ksh93, zsh, yash), you can also do:

$ printf '%.3f\n' "$((ERRORS * 1e2 / TOTAL))"

(though note that in zsh and ksh93, it's critical the contents of those variables be controlled as that would constitute a command injection vulnerability if not. We use 1e2 (a floating point 100 while 100 is integer) instead of 100. as in ksh93, 100. wouldn't work in locales that use , as the decimal radix).

Or you could use awk:

$ awk -- 'BEGIN{printf "%.3f\n", ARGV[1] * 100 / ARGV[2]}' "$ERRORS" "$TOTAL"

Both of which would give you 88.889% (or possibly 88,889 depending on the locale) for 8 out of 9.


Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.