Sample output
$ echo $(( 2 / 3 ))
0
$ echo '2/3' | bc
0
$ echo 'scale=3; 2/3' | bc
.666
Two oddities in one line. The answer is truncated rather than rounded, so 0.6666 becomes .666, not .667, and bc drops the leading zero before the decimal point. Both are correct according to the language. Neither looks like what you expected, and the variants below fix each.
When you would reach for it
Shell arithmetic is integer only, so any script that turns bytes into gigabytes, works out a percentage, or averages a column of response times either drops the fraction or needs help. bc is that help, and it is already on the machine. It also handles numbers too large for $(( )), which wraps around silently once a value passes 2^63 - 1.
Gotchas
- Truncation happens at every division, not once at the end, so order matters.
scale=1; 37 / 52 * 100prints70.0, whilescale=1; 100 * 37 / 52prints71.1. The first version cuts 0.7115 down to 0.7 before multiplying. Multiply first, divide last, or setscalea few digits higher than you need and round at the end. scaledoes not limit multiplication.scale=0; 1.5*3still prints4.5, because a product keeps the decimals of its operands. Division,%,^, andsqrt()respectscale;*,+, and-mostly ignore it. Runningbc -lsetsscaleto 20 and loads the math library, which is why it seems to fix everything at once.ibasechanges how every number after it is read, including the next assignment.ibase=16; obase=10; FFprintsFF, not 255, because the10was read in hex and set the output base to 16. Setobasefirst, or writeobase=Awhen the input base is already 16.- Results wider than 70 characters wrap with a trailing backslash, which breaks anything parsing the output. Set
BC_LINE_LENGTH=0in the environment to turn the wrapping off. GNU bc on Debian and the bc that ships with macOS both honor it. Minimal container images, Alpine anddebian:bookworm-slimamong them, often leave bc out entirely, soapk add bcorapt install bcbefore a script depends on it.
Variants
$ printf '%.2f\n' "$(echo '2/3' | bc -l)"
Rounding and the leading zero in one step. bc computes at 20 digits, then printf rounds to two and prints 0.67
$ bytes=$(wc -c < large-file.img); bc <<< "scale=2; $bytes / 1024 / 1024"
Bash and zsh. A here-string replaces the echo, and double quotes let the shell splice a measured value into the expression. Prints 5.00 for a 5 MB file
$ echo 'obase=16; ibase=2; 11111111' | bc
Base conversion in either direction, with the assignments in the safe order. Prints FF