Text processing
bc
An arbitrary-precision calculator language, used from scripts for decimal math the shell cannot do.
bc [-lqs] [FILE...]
bash arithmetic, $(( )), only knows integers. When a script needs decimals, very large
numbers or base conversion, the usual answer is to pipe an expression into bc: it reads
statements from standard input or files, evaluates them, and prints each result.
Two settings explain almost every surprise. scale is the number of digits kept after the
decimal point in division and other operations, and it starts at 0, so 10 / 3 is 3.
Starting bc with -l loads the math library, sets scale to 20 and adds s(), c(), a(),
l(), e() (sine, cosine, arctangent, natural log, exponential). Results are truncated to
scale, not rounded.
For simple float formatting awk or printf '%.2f' is often enough; reach for bc when you
need exact decimal arithmetic or numbers larger than 64 bits.
Examples
Evaluate an expression
echo '2 + 3 * 4' | bc
14
bc follows the usual precedence, so multiplication happens first and the result is 14.
Division is integer until you set scale
echo '10 / 3' | bc
echo 'scale=2; 10 / 3' | bc
3 3.33
With the default scale of 0 the fraction is dropped. scale=2 keeps two decimal places.
Statements are separated by ; or newlines.
Use the math library with -l
echo '10 / 3; sqrt(2); 4 * a(1)' | bc -l
3.33333333333333333333 1.41421356237309504880 3.14159265358979323844
-l sets scale to 20 and loads the math functions. a(1) is the arctangent of 1, a
quarter of pi, so 4 * a(1) prints pi to 20 decimal places. sqrt is built in and also
honors scale.
Use the result in a shell script
units=92; revenue=743.36
avg=$(echo "scale=2; $revenue / $units" | bc)
echo "average price: $avg"
average price: 8.08
Double quotes let the shell insert the variables into the expression, and command
substitution captures the answer. bc omits the leading zero for values below 1, which is
why the result prints as 8.08 here but would be .50 for a half.
bc truncates instead of rounding
echo 'scale=2; 2 / 3' | bc
printf '%.2f\n' "$(echo 'scale=10; 2 / 3' | bc)"
.66 0.67
With scale=2 the result is cut to .66. To round, compute with extra digits and let
printf round to the precision you want, giving 0.67 (with the leading zero restored).
Compare decimal numbers
load=3.75; limit=2.5
if (( $(echo "$load > $limit" | bc) )); then echo "load $load is over $limit"; fi
load 3.75 is over 2.5
bash's [ ] and (( )) only compare integers. bc prints 1 for a true comparison and 0
for false, which (( )) then tests.
Add up a column of numbers
paste -sd+ data/numbers.txt | bc
324
paste -sd+ joins the lines of the file with + into one expression, 42+7+19+..., and
bc evaluates it. Works for decimals too, unlike $(( )).
Calculate with very large numbers
echo '2^100; 2^64 - 1' | bc
1267650600228229401496703205376 18446744073709551615
bc's precision is limited only by memory. bash arithmetic would overflow at 64 bits;
2^64 - 1 is the largest unsigned 64-bit integer. ^ takes integer exponents only.
Convert between number bases
echo 'obase=16; 255' | bc
echo 'obase=2; 10' | bc
echo 'ibase=16; FF' | bc
FF 1010 255
obase sets the output base and ibase the input base. Hex digits must be uppercase. Set
obase before ibase: once ibase=16, a later obase=10 would be read as hex 10, which
is 16.
Run a multi-line calculation
bc -l <<'EOF'
principal = 10000
rate = 0.05
years = 10
total = principal * e(years * l(1 + rate))
scale = 2
total / 1
EOF
16288.94
bc is a small language with variables, if, while, for and functions. This computes
compound interest: l() is the natural log and e() the exponential, so total is
principal times (1 + rate) to the power of years, worked out at 20 digits. Only then is
scale lowered; dividing by 1 applies it and truncates to cents. Setting scale = 2 at
the top would make l() and e() work at two digits and print a badly wrong 14900.00.
Errors do not change the exit status
echo '1 / 0' | bc; echo "exit status: $?"
Runtime error (func=(main), adr=3): Divide by zero exit status: 0
bc prints a runtime error on stderr but still exits with status 0. Scripts must check the
output, for example that it is non-empty, rather than rely on $?.
Common pitfalls
scaledefaults to 0, soecho '7/2' | bcprints3. Setscaleor use-l.Results below 1 have no leading zero (
.5). Pass the value throughprintf '%.2f'if something downstream expects0.5.Long results are wrapped with a backslash at 70 characters. GNU bc reads
BC_LINE_LENGTH;BC_LINE_LENGTH=0turns wrapping off.ibaseaffects every later number, including the ones inobase=.... Setobasefirst.Errors such as division by zero or a syntax error print a message but leave the exit status at 0.
GNU vs BSD and macOS
The examples above ran the GNU/Linux version. These are the differences that matter on macOS and the BSDs (written from their documentation, not run here).
Debian and Ubuntu ship GNU bc; recent macOS and FreeBSD ship a different implementation (Gavin Howard's bc). Both accept the POSIX language and
-l, but their error messages and non-POSIX extensions differ, so test scripts on both if you rely on extensions.
Options worth knowing
A selection, described in our own words. For the full list, see bc(1) or bc --help.
| Option | What it does |
|---|---|
-l, --mathlib | Load the math library and set scale to 20. |
-q, --quiet | Do not print the welcome banner in interactive mode. |
-s, --standard | Process exactly the POSIX bc language. |
-w, --warn | Warn about extensions to POSIX bc. |
-i, --interactive | Force interactive mode. |
Related
exprEvaluate an integer, comparison or string expression given as separate arguments and print the result.awkScan text as records and fields, and run a small program on each line that matches a pattern.printfPrint text and values through a format string, with precise control over spacing, numbers and escapes.seqPrint a sequence of numbers, with a chosen start, step, separator and format.pasteMerge lines of files side by side, or join all lines of one file into a single line.- ArithmeticInteger math with $(( )) and (( )), the exit status of (( )) that breaks set -e, leading-zero octal surprises, and what to use for decimals.
- Command substitutionCapturing a command's output with $(...), what happens to trailing newlines and stderr, how to check the exit status, and the local trap that hides failures.
- Here-documents and here-stringsFeed multi-line text to a command with <<EOF, stop expansion with a quoted delimiter, indent with <<-, and pass one string with <<<.